This is the code for the statistical analysis for “Vowel Acoustics as Predictors of Speech Intelligibility in Dysarthria.”

Loading Packages

This block of code loads in the required packages for this script. In the #’s, I have provided to the code to install each package if needed.


library(rio) # install.packages('rio')
library(tidyverse) # install.packages('tidyverse')
library(irr) # install.packages('irr')
library(performance) # install.packages('performance')
library(car) # install.packages('car')
library(ggpubr) # install.packages('ggpubr')
library(Hmisc) # install.packages('Hmisc')
library(ggridges) # install.packages('ggridges')
library(furniture) # install.packages('furniture')
library(gt) # install.packages('gt')
library(patchwork) # install.packages('patchwork')
library(ks) # install.packages('ks')
library(emuR) # install.packages('emuR')
library(mslTools) # devtools::install_github("AustinRThompson/mslTools")

Upload Datasets


Reliability <- rio::import("Prepped Data/Reliability Data.csv")
AcousticData <- rio::import("Prepped Data/AcousticMeasures.csv") %>%
  dplyr::mutate(intDiff = VAS - transAcc)

AcousticData <- AcousticData %>%
  dplyr::filter(!grepl("_rel", Speaker)) %>%
  dplyr::select(c(Speaker, Sex, Etiology, vowel_ED_b, VSA_b,
                  Hull_b,Hull_bVSD_25, Hull_bVSD_50, Hull_bVSD_75,
                  VAS, transAcc)) %>%
  dplyr::mutate(Etiology = as.factor(Etiology),
                Sex = as.factor(Sex),
                Speaker = as.factor(Speaker))

Listeners <- rio::import("Prepped Data/Listener_Demographics.csv") %>%
  dplyr::select(!c(StartDate:proloficID, Q2.4_6_TEXT, Q3.2_8_TEXT, AudioCheck:EP3))

Listeners$race[Listeners$Q3.3_7_TEXT == "Native American/ African amercing"] <- "Biracial or Multiracial"

Inter-rater Reliability

Two raters (the first two authors) completed vowel segmentation for the speakers. To calculate inter-rater reliability, 20% of the speakers were segmented again by the other rater. Two-way intraclass coefficients were computed for the extracted F1 and F2 from the temporal midpoint of the vowel segments. Since only one set of ratings will be used in the data analysis, we focus on the single ICC results and interpretation. However, we also report the average ICC values to be comprehensive.


## Creating new data frames to calculate ICC for extracted F1 and F2 values

F1_Rel <- Reliability %>%
  dplyr::select(c(F1, F1_rel))

F2_Rel <- Reliability %>%
  dplyr::select(c(F2, F2_rel))
  
## Single ICC for F1
Single_F1 <- irr::icc(F1_Rel, model = "twoway", type = "agreement", unit = "single")

## Average ICC for F1
Average_F1 <- irr::icc(F1_Rel, model = "twoway", type = "agreement", unit = "average")

## Single ICC for F2
Single_F2 <- irr::icc(F2_Rel, model = "twoway", type = "agreement", unit = "single")

## Average ICC for F2
Average_F2 <- irr::icc(F2_Rel, model = "twoway", type = "agreement", unit = "average")

## Inter-rater reliability results and interpretation
  print(paste("Single ICC for F1 is ",
              round(Single_F1$value, digits = 3),
              ". ", 
              "The 95% CI is [",
              round(Single_F1$lbound, digits = 3),
              " - ",
              round(Single_F1$ubound, digits = 3),
              "].",
              sep = ""))
[1] "Single ICC for F1 is 0.866. The 95% CI is [0.837 - 0.89]."
  
  print(paste("Single ICC for F2 is ",
              round(Single_F2$value, digits = 3),
              ". ", 
              "The 95% CI is [",
              round(Single_F2$lbound, digits = 3),
              " - ", round(Single_F2$ubound, digits = 3),
              "].",
              sep = ""))
[1] "Single ICC for F2 is 0.931. The 95% CI is [0.916 - 0.944]."
  
  print(paste("Average ICC for F1 is ",
              round(Average_F1$value, digits = 3),
              ". ", 
              "The 95% CI is [",
              round(Average_F1$lbound, digits = 3),
              " - ",
              round(Average_F1$ubound, digits = 3),
              "].",
              sep = ""))
[1] "Average ICC for F1 is 0.928. The 95% CI is [0.911 - 0.942]."
  
  print(paste("Average ICC for F2 is ",
              round(Average_F2$value, digits = 3),
              ". ", 
              "The 95% CI is [",
              round(Average_F2$lbound, digits = 3),
              " - ",
              round(Average_F2$ubound, digits = 3),
              "].",
              sep = ""))
[1] "Average ICC for F2 is 0.964. The 95% CI is [0.956 - 0.971]."
  
  print("Thus, interrater reliability for the extracted F1 and F2 values from the vowel segments was good to excellent.")
[1] "Thus, interrater reliability for the extracted F1 and F2 values from the vowel segments was good to excellent."
## Removing extra data frames from environment
rm(F1_Rel, F2_Rel, Reliability, Single_F1, Single_F2, Average_F1, Average_F2)

Descriptive Statistics

Correlations

CorrMatrix
                 VSA_b vowel_ED_b    Hull_b Hull_bVSD_25 Hull_bVSD_75       VAS   transAcc
VSA_b        1.0000000  0.7270881 0.5542294    0.5175807   0.28240421 0.4858562 0.50853397
vowel_ED_b   0.7270881  1.0000000 0.4864838    0.3988742   0.12768894 0.4016545 0.42055730
Hull_b       0.5542294  0.4864838 1.0000000    0.8386250   0.45558161 0.2544806 0.28921519
Hull_bVSD_25 0.5175807  0.3988742 0.8386250    1.0000000   0.67628366 0.1507205 0.18077432
Hull_bVSD_75 0.2824042  0.1276889 0.4555816    0.6762837   1.00000000 0.0916510 0.08543956
VAS          0.4858562  0.4016545 0.2544806    0.1507205   0.09165100 1.0000000 0.94571449
transAcc     0.5085340  0.4205573 0.2892152    0.1807743   0.08543956 0.9457145 1.00000000

Research Q1: Modeling Intelligibility

Orthographic Transcriptions

Model 1


# Specifying Model 1
OT_Model1 <- lm(transAcc ~ Hull_bVSD_25, data = AcousticData)

## Model 1 Assumptions 
performance::check_model(OT_Model1)


## Model 1 Summary
summary(OT_Model1)

Call:
lm(formula = transAcc ~ Hull_bVSD_25, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-47.896 -14.090   5.996  17.470  36.105 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)   48.2973     9.7372   4.960  1.5e-05 ***
Hull_bVSD_25   0.6417     0.5663   1.133    0.264    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 23.83 on 38 degrees of freedom
Multiple R-squared:  0.03268,   Adjusted R-squared:  0.007224 
F-statistic: 1.284 on 1 and 38 DF,  p-value: 0.2643

Model 2


## Specifying Model 2
OT_Model2 <- lm(transAcc ~ Hull_bVSD_25 + Hull_bVSD_75, data = AcousticData)

## Model 2 Assumption Check
performance::check_model(OT_Model2)


## Model 2 Summary
summary(OT_Model2)

Call:
lm(formula = transAcc ~ Hull_bVSD_25 + Hull_bVSD_75, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-48.854 -13.962   5.567  16.758  36.257 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)   47.3374    10.3316   4.582 5.09e-05 ***
Hull_bVSD_25   0.8045     0.7781   1.034    0.308    
Hull_bVSD_75  -0.7188     2.3225  -0.309    0.759    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24.11 on 37 degrees of freedom
Multiple R-squared:  0.03518,   Adjusted R-squared:  -0.01698 
F-statistic: 0.6745 on 2 and 37 DF,  p-value: 0.5156
## Model 1 and Model 2 Comparison
anova(OT_Model1, OT_Model2)
Analysis of Variance Table

Model 1: transAcc ~ Hull_bVSD_25
Model 2: transAcc ~ Hull_bVSD_25 + Hull_bVSD_75
  Res.Df   RSS Df Sum of Sq      F Pr(>F)
1     38 21570                           
2     37 21514  1    55.696 0.0958 0.7587

Model 3a


## Specifying Model 3
OT_Model3a <- lm(transAcc ~ Hull_bVSD_25 + Hull_bVSD_75 + Hull_b, data = AcousticData)

## Model 3 Assumption Check
performance::check_model(OT_Model3a)

performance::check_collinearity(OT_Model3a)
# Check for Multicollinearity

Low Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_75 2.00         1.41      0.50
       Hull_b 3.65         1.91      0.27

Moderate Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_25 5.33         2.31      0.19
## Model 3 Summary
summary(OT_Model3a)

Call:
lm(formula = transAcc ~ Hull_bVSD_25 + Hull_bVSD_75 + Hull_b, 
    data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-56.706 -13.157   7.018  17.957  29.990 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept)   31.0806    14.4916   2.145   0.0388 *
Hull_bVSD_25  -0.8439     1.2984  -0.650   0.5199  
Hull_bVSD_75   0.3159     2.3714   0.133   0.8948  
Hull_b         1.2941     0.8247   1.569   0.1253  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 23.65 on 36 degrees of freedom
Multiple R-squared:  0.09695,   Adjusted R-squared:  0.0217 
F-statistic: 1.288 on 3 and 36 DF,  p-value: 0.2932
## Model 2 and Model 3 Comparison
anova(OT_Model2, OT_Model3a)
Analysis of Variance Table

Model 1: transAcc ~ Hull_bVSD_25 + Hull_bVSD_75
Model 2: transAcc ~ Hull_bVSD_25 + Hull_bVSD_75 + Hull_b
  Res.Df   RSS Df Sum of Sq      F Pr(>F)
1     37 21514                           
2     36 20137  1    1377.5 2.4626 0.1253

Model 3b


## Specifying Model 3

OT_Model3b <- lm(transAcc ~ Hull_bVSD_75 + Hull_b, data = AcousticData)

## Model 3 Assumption Check

performance::check_model(OT_Model3b)

performance::check_collinearity(OT_Model3b)
# Check for Multicollinearity

Low Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_75 1.26         1.12      0.79
       Hull_b 1.26         1.12      0.79
## Model 3 Summary

summary(OT_Model3b)

Call:
lm(formula = transAcc ~ Hull_bVSD_75 + Hull_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-54.371 -12.860   5.038  17.725  31.609 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept)   33.2337    13.9973   2.374   0.0229 *
Hull_bVSD_75  -0.6193     1.8702  -0.331   0.7424  
Hull_b         0.8605     0.4809   1.789   0.0818 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 23.47 on 37 degrees of freedom
Multiple R-squared:  0.08635,   Adjusted R-squared:  0.03697 
F-statistic: 1.749 on 2 and 37 DF,  p-value: 0.1881

Model 4


## Specifying Model 4

OT_Model4 <- lm(transAcc ~ Hull_bVSD_75 + Hull_b + VSA_b, data = AcousticData)

## Model 4 Assumption Check

performance::check_model(OT_Model4)

performance::check_collinearity(OT_Model4)
# Check for Multicollinearity

Low Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_75 1.26         1.12      0.79
       Hull_b 1.68         1.30      0.60
        VSA_b 1.45         1.20      0.69
## Model 4 Summary

summary(OT_Model4)

Call:
lm(formula = transAcc ~ Hull_bVSD_75 + Hull_b + VSA_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-47.705 -12.573   3.108  14.504  35.215 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)   
(Intercept)   30.7726    12.7686   2.410  0.02119 * 
Hull_bVSD_75  -0.8216     1.7037  -0.482  0.63256   
Hull_b         0.1202     0.5049   0.238  0.81322   
VSA_b          5.8426     1.9859   2.942  0.00567 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 21.36 on 36 degrees of freedom
Multiple R-squared:  0.2634,    Adjusted R-squared:  0.2021 
F-statistic: 4.292 on 3 and 36 DF,  p-value: 0.01092
## Model 3 and Model 4 Comparison

anova(OT_Model3b, OT_Model4)
Analysis of Variance Table

Model 1: transAcc ~ Hull_bVSD_75 + Hull_b
Model 2: transAcc ~ Hull_bVSD_75 + Hull_b + VSA_b
  Res.Df   RSS Df Sum of Sq      F   Pr(>F)   
1     37 20373                                
2     36 16424  1    3948.9 8.6555 0.005673 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Model 5


## Specifying Model 5

OT_Model5 <- lm(transAcc ~ Hull_bVSD_75 + VSA_b + vowel_ED_b, data = AcousticData)

## Model 4 Assumption Check

performance::check_model(OT_Model5)

performance::check_collinearity(OT_Model5)
# Check for Multicollinearity

Low Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_75 1.10         1.05      0.91
        VSA_b 2.30         1.52      0.43
   vowel_ED_b 2.15         1.47      0.46
## Model 4 Summary

summary(OT_Model5)

Call:
lm(formula = transAcc ~ Hull_bVSD_75 + VSA_b + vowel_ED_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-46.501 -11.965   2.561  14.356  33.849 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept)   24.4273    20.1254   1.214   0.2327  
Hull_bVSD_75  -0.5814     1.5872  -0.366   0.7163  
VSA_b          5.2219     2.4990   2.090   0.0438 *
vowel_ED_b     6.0028    12.7240   0.472   0.6399  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 21.31 on 36 degrees of freedom
Multiple R-squared:  0.2668,    Adjusted R-squared:  0.2057 
F-statistic: 4.367 on 3 and 36 DF,  p-value: 0.0101
## Model 3 and Model 4 Comparison

anova(OT_Model4, OT_Model5)
Analysis of Variance Table

Model 1: transAcc ~ Hull_bVSD_75 + Hull_b + VSA_b
Model 2: transAcc ~ Hull_bVSD_75 + VSA_b + vowel_ED_b
  Res.Df   RSS Df Sum of Sq F Pr(>F)
1     36 16424                      
2     36 16349  0    75.229         

Final Model


## Specifying Final Model

OT_Model_final <- lm(transAcc ~ VSA_b, data = AcousticData)

## Final Model Assumption Check

performance::check_model(OT_Model_final)


## Final Model Summary

summary(OT_Model_final)

Call:
lm(formula = transAcc ~ VSA_b, data = AcousticData)

Residuals:
   Min     1Q Median     3Q    Max 
-46.72 -12.69   2.97  14.37  35.39 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   32.508      7.857   4.138 0.000187 ***
VSA_b          5.872      1.613   3.641 0.000807 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 20.86 on 38 degrees of freedom
Multiple R-squared:  0.2586,    Adjusted R-squared:  0.2391 
F-statistic: 13.25 on 1 and 38 DF,  p-value: 0.0008068
confint(OT_Model_final)
                2.5 %    97.5 %
(Intercept) 16.602765 48.413532
VSA_b        2.606927  9.137097

VAS Models

Model 1


# Specifying Model 1

VAS_Model1 <- lm(VAS ~ Hull_bVSD_25, data = AcousticData)

## Model 1 Assumptions 

performance::check_model(VAS_Model1)


## Model 1 Summary

summary(VAS_Model1)

Call:
lm(formula = VAS ~ Hull_bVSD_25, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-47.625 -16.684   8.462  19.440  37.352 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)   42.6328    10.7512   3.965 0.000313 ***
Hull_bVSD_25   0.5877     0.6253   0.940 0.353236    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 26.31 on 38 degrees of freedom
Multiple R-squared:  0.02272,   Adjusted R-squared:  -0.003001 
F-statistic: 0.8833 on 1 and 38 DF,  p-value: 0.3532

Model 2


## Specifying Model 2

VAS_Model2 <- lm(VAS ~ Hull_bVSD_25 + Hull_bVSD_75, data = AcousticData)

## Model 2 Assumption Check

performance::check_model(VAS_Model2)


## Model 2 Summary

summary(VAS_Model2)

Call:
lm(formula = VAS ~ Hull_bVSD_25 + Hull_bVSD_75, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-47.850 -16.576   8.382  19.448  37.237 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)   42.3384    11.4211   3.707 0.000684 ***
Hull_bVSD_25   0.6376     0.8602   0.741 0.463195    
Hull_bVSD_75  -0.2204     2.5674  -0.086 0.932036    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 26.66 on 37 degrees of freedom
Multiple R-squared:  0.02291,   Adjusted R-squared:  -0.0299 
F-statistic: 0.4338 on 2 and 37 DF,  p-value: 0.6513
## Model 1 and Model 2 Comparison

anova(VAS_Model1, VAS_Model2)
Analysis of Variance Table

Model 1: VAS ~ Hull_bVSD_25
Model 2: VAS ~ Hull_bVSD_25 + Hull_bVSD_75
  Res.Df   RSS Df Sum of Sq      F Pr(>F)
1     38 26296                           
2     37 26291  1     5.239 0.0074  0.932

Model 3a


## Specifying Model 3

VAS_Model3a <- lm(VAS ~ Hull_bVSD_25 + Hull_bVSD_75 + Hull_b, data = AcousticData)

## Model 3 Assumption Check

performance::check_model(VAS_Model3a)

performance::check_collinearity(VAS_Model3a)
# Check for Multicollinearity

Low Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_75 2.00         1.41      0.50
       Hull_b 3.65         1.91      0.27

Moderate Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_25 5.33         2.31      0.19
## Model 3 Summary

summary(VAS_Model3a)

Call:
lm(formula = VAS ~ Hull_bVSD_25 + Hull_bVSD_75 + Hull_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-56.444 -18.989   6.121  18.036  32.281 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)
(Intercept)   25.0400    16.0599   1.559    0.128
Hull_bVSD_25  -1.1164     1.4389  -0.776    0.443
Hull_bVSD_75   0.8805     2.6280   0.335    0.740
Hull_b         1.3770     0.9139   1.507    0.141

Residual standard error: 26.21 on 36 degrees of freedom
Multiple R-squared:  0.08087,   Adjusted R-squared:  0.00428 
F-statistic: 1.056 on 3 and 36 DF,  p-value: 0.3799
## Model 2 and Model 3 Comparison

anova(VAS_Model2, VAS_Model3a)
Analysis of Variance Table

Model 1: VAS ~ Hull_bVSD_25 + Hull_bVSD_75
Model 2: VAS ~ Hull_bVSD_25 + Hull_bVSD_75 + Hull_b
  Res.Df   RSS Df Sum of Sq      F Pr(>F)
1     37 26291                           
2     36 24731  1    1559.6 2.2702 0.1406

Model 3b

This model removes VSD25 because of it’s high VIF value > 5.


## Specifying Model 3b

VAS_Model3b <- lm(VAS ~ Hull_bVSD_75 + Hull_b, data = AcousticData)

## Model 3 Assumption Check

performance::check_model(VAS_Model3b)

performance::check_collinearity(VAS_Model3b)
# Check for Multicollinearity

Low Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_75 1.26         1.12      0.79
       Hull_b 1.26         1.12      0.79
## Model 3 Summary

summary(VAS_Model3b)

Call:
lm(formula = VAS ~ Hull_bVSD_75 + Hull_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-53.356 -19.394   8.036  21.298  33.412 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept)   27.8884    15.5503   1.793   0.0811 .
Hull_bVSD_75  -0.3567     2.0777  -0.172   0.8646  
Hull_b         0.8034     0.5343   1.504   0.1412  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 26.07 on 37 degrees of freedom
Multiple R-squared:  0.0655,    Adjusted R-squared:  0.01499 
F-statistic: 1.297 on 2 and 37 DF,  p-value: 0.2855

Model 4


## Specifying Model 4

VAS_Model4 <- lm(VAS ~ Hull_bVSD_75 + Hull_b + VSA_b, data = AcousticData)

## Model 4 Assumption Check

performance::check_model(VAS_Model4)

performance::check_collinearity(VAS_Model4)
# Check for Multicollinearity

Low Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_75 1.26         1.12      0.79
       Hull_b 1.68         1.30      0.60
        VSA_b 1.45         1.20      0.69
## Model 4 Summary

summary(VAS_Model4)

Call:
lm(formula = VAS ~ Hull_bVSD_75 + Hull_b + VSA_b, data = AcousticData)

Residuals:
   Min     1Q Median     3Q    Max 
-45.56 -15.17   6.40  16.64  42.62 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)   
(Intercept)   2.522e+01  1.426e+01   1.768  0.08553 . 
Hull_bVSD_75 -5.762e-01  1.903e+00  -0.303  0.76382   
Hull_b        5.056e-05  5.640e-01   0.000  0.99993   
VSA_b         6.340e+00  2.218e+00   2.858  0.00705 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 23.86 on 36 degrees of freedom
Multiple R-squared:  0.2383,    Adjusted R-squared:  0.1748 
F-statistic: 3.754 on 3 and 36 DF,  p-value: 0.01916
## Model 3 and Model 4 Comparison

anova(VAS_Model3b, VAS_Model4)
Analysis of Variance Table

Model 1: VAS ~ Hull_bVSD_75 + Hull_b
Model 2: VAS ~ Hull_bVSD_75 + Hull_b + VSA_b
  Res.Df   RSS Df Sum of Sq      F   Pr(>F)   
1     37 25145                                
2     36 20495  1    4649.8 8.1674 0.007046 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Model 5


## Specifying Model 5

VAS_Model5 <- lm(VAS ~ Hull_bVSD_75 + Hull_b + VSA_b + vowel_ED_b, data = AcousticData)

## Model 5 Assumption Check

performance::check_model(VAS_Model5)


## Model 5 Summary

summary(VAS_Model5)

Call:
lm(formula = VAS ~ Hull_bVSD_75 + Hull_b + VSA_b + vowel_ED_b, 
    data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-44.407 -13.917   7.397  16.408  41.322 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept)  16.61280   23.81590   0.698    0.490  
Hull_bVSD_75 -0.40875    1.95955  -0.209    0.836  
Hull_b       -0.05465    0.58294  -0.094    0.926  
VSA_b         5.49348    2.91674   1.883    0.068 .
vowel_ED_b    6.68540   14.72389   0.454    0.653  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24.13 on 35 degrees of freedom
Multiple R-squared:  0.2428,    Adjusted R-squared:  0.1562 
F-statistic: 2.805 on 4 and 35 DF,  p-value: 0.04041
## Model 4 and Model 5 Comparison

anova(VAS_Model4, VAS_Model5)
Analysis of Variance Table

Model 1: VAS ~ Hull_bVSD_75 + Hull_b + VSA_b
Model 2: VAS ~ Hull_bVSD_75 + Hull_b + VSA_b + vowel_ED_b
  Res.Df   RSS Df Sum of Sq      F Pr(>F)
1     36 20495                           
2     35 20375  1    120.02 0.2062 0.6526

Final Model


## Specifying Final Model

VAS_Model_final <- lm(VAS ~ VSA_b, data = AcousticData)

## Final Model Assumption Check

performance::check_model(VAS_Model_final)


## Final Model Summary

summary(VAS_Model_final)

Call:
lm(formula = VAS ~ VSA_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-44.956 -15.943   6.754  17.153  43.062 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)   
(Intercept)   24.703      8.761   2.820  0.00760 **
VSA_b          6.163      1.798   3.427  0.00148 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 23.26 on 38 degrees of freedom
Multiple R-squared:  0.2361,    Adjusted R-squared:  0.216 
F-statistic: 11.74 on 1 and 38 DF,  p-value: 0.001482
confint(VAS_Model_final)
               2.5 %    97.5 %
(Intercept) 6.966936 42.438084
VSA_b       2.521887  9.803467

Research Q2: Relationship between OT and VAS

Model 1


# Specify Model

OT_VAS_model <- lm(transAcc ~ VAS*Etiology + VAS*Sex, data = AcousticData)

# Assumption Check

performance::check_model(OT_VAS_model)

# Model Results

summary(OT_VAS_model)

Final Linear Model


# Specify Final Model

OT_VAS_final <- lm(transAcc ~ VAS, data = AcousticData)

confint(OT_VAS_final)

# Model Results

summary(OT_VAS_final)

Corner Dispersion

Looking at corner dispersion as the sole predictor.


# Specify Final Model

OT_cornDisp <- lm(transAcc ~ vowel_ED_b, data = AcousticData)
summary(OT_cornDisp)

Call:
lm(formula = transAcc ~ vowel_ED_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-53.949 -10.348   4.268  14.982  25.903 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)   
(Intercept)    6.227     18.611   0.335  0.73977   
vowel_ED_b    25.564      8.946   2.857  0.00689 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 21.98 on 38 degrees of freedom
Multiple R-squared:  0.1769,    Adjusted R-squared:  0.1552 
F-statistic: 8.165 on 1 and 38 DF,  p-value: 0.006891
VAS_cornDisp <- lm(VAS ~ vowel_ED_b, data = AcousticData)
summary(VAS_cornDisp)

Call:
lm(formula = VAS ~ vowel_ED_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-52.146 -13.413   7.142  18.719  32.964 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)  
(Intercept)   -2.859     20.636  -0.139   0.8905  
vowel_ED_b    26.819      9.920   2.704   0.0102 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24.37 on 38 degrees of freedom
Multiple R-squared:  0.1613,    Adjusted R-squared:  0.1393 
F-statistic:  7.31 on 1 and 38 DF,  p-value: 0.0102

Manuscript Tables

Descriptives Table

gtData <- AcousticData %>%
  rbind(.,AcousticData %>%
          dplyr::mutate(Etiology = "All Etiologies")) %>%
  rbind(.,AcousticData %>%
          rbind(.,AcousticData %>%
          dplyr::mutate(Etiology = "All Etiologies")) %>%
          dplyr::mutate(Sex = "All")) %>%
  dplyr::mutate(Sex = as.factor(Sex),
                Etiology = as.factor(Etiology)) %>%
  dplyr::group_by(Sex, Etiology) %>%
  dplyr::summarize(VSA_mean = mean(VSA_b, na.rm =T), VSA_sd = sd(VSA_b, na.rm = T),
                   Disp_mean = mean(vowel_ED_b, na.rm =T), Disp_sd = sd(vowel_ED_b, na.rm =T),
                   Hull_mean = mean(Hull_b, na.rm =T), Hull_sd = sd(Hull_b, na.rm =T),
                   VSD25_mean = mean(Hull_bVSD_25, na.rm =T), VSD25_sd = sd(Hull_bVSD_25, na.rm =T),
                   VSD50_mean = mean(Hull_bVSD_50, na.rm =T), VSD50_sd = sd(Hull_bVSD_50, na.rm =T),
                   VSD75_mean = mean(Hull_bVSD_75, na.rm =T), VSD75_sd = sd(Hull_bVSD_75, na.rm =T),
                   VAS_mean = mean(VAS, na.rm =T), VAS_sd = sd(VAS, na.rm =T),
                   OT_mean = mean(transAcc, na.rm =T), OT_sd = sd(transAcc, na.rm =T)) %>%
  pivot_longer(cols = VSA_mean:OT_sd, names_to = "Measure",
               values_to = "Value") %>%
  dplyr::mutate(Value = round(Value, digits = 2),
                meanSD = ifelse(grepl("_mean",Measure),"M","sd"),
                Measure = gsub("_mean","",Measure),
                Measure = gsub("_sd","",Measure),
                Etiology = paste(Etiology,meanSD, sep = "_"),
                Sex = case_when(
                  Sex == "All" ~ "All Speakers",
                  Sex == "M" ~ "Male Speakers",
                  Sex == "F" ~ "Female Speakers"
                )) %>%
  dplyr::select(!meanSD) %>%
  pivot_wider(names_from = Etiology, values_from = "Value") %>%
  dplyr::filter(Measure != "VSD50")
`summarise()` has grouped output by 'Sex'. You can override using the `.groups` argument.
gtData %>%
  gt::gt(
    rowname_col = "Measure",
    groupname_col = "Sex",
  ) %>%
  fmt_number(
    columns = 'All Etiologies_M':PD_sd,
    decimals = 2
  ) %>%
  tab_spanner(
    label = "All Etiologies",
    columns = c('All Etiologies_M', 'All Etiologies_sd')
  ) %>%
    tab_spanner(
    label = "ALS",
    columns = c(ALS_M, ALS_sd)
  ) %>%
  tab_spanner(
    label = "PD",
    columns = c(PD_M, PD_sd)
  ) %>%
  tab_spanner(
    label = "HD",
    columns = c(HD_M, HD_sd)
  ) %>%
  tab_spanner(
    label = "Ataxic",
    columns = c(Ataxic_M, Ataxic_sd)
  ) %>%
  gt::cols_move_to_start(
    columns = c('All Etiologies_M','All Etiologies_sd')
  ) %>%
  row_group_order(
    groups = c("All Speakers", "Female Speakers", "Male Speakers")
    ) %>%
  cols_label(
     'All Etiologies_M' = "M",
     'All Etiologies_sd' = "SD",
     ALS_M = "M",
     ALS_sd = "SD",
     PD_M = "M",
     PD_sd = "SD",
     HD_M = "M",
     HD_sd = "SD",
     Ataxic_M = "M",
     Ataxic_sd = "SD"
  ) %>%
  gtsave("DescriptivesTable.html", path = "Tables")

OT Model

sjPlot::tab_model(OT_Model1,
                  OT_Model2,
                  OT_Model3b,
                  OT_Model4,
                  OT_Model5,
                  OT_Model_final,
                  show.ci = F,
                  p.style = "stars",
                  file = "Tables/OT Models.html")

VAS Model

sjPlot::tab_model(VAS_Model1,
                  VAS_Model2,
                  VAS_Model3,
                  VAS_Model4,
                  VAS_Model5,
                  VAS_Model_final,
                  show.ci = F,
                  p.style = "stars",
                  file = "Tables/VAS Models.html")

OT vs. VAS

sjPlot::tab_model(OT_VAS_model,OT_VAS_final,
                  show.ci = F,
                  show.reflvl = TRUE,
                  p.style = "stars",
                  file = "Tables/OT and VAS Comparison.html")

Manuscript Figures

Example Measures

formantColor <- "grey"
formantAlpha <- .95
lineColor <- "white"
lineAlpha <- .8

vowelData <- rio::import("Prepped Data/Vowel Data.csv") %>%
  dplyr::filter(Speaker == "AF8")

  Pitch_PRAAT <- list.files(path = paste("Prepped Data/Example Data/", sep = ""), 
                              pattern = ".Pitch", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = F) %>%
    dplyr::rename(Pitch = V1) %>%
    dplyr::mutate(Pitch = gsub("--undefined--",NA,Pitch),
                  Pitch = as.numeric(Pitch))
  
  Formants_PRAAT <- list.files(path = paste("Prepped Data/Example Data/", sep = ""), 
                              pattern = "_Formant", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = T) %>%
    dplyr::select(!c(nformants, B1.Hz., B2.Hz., B3.Hz., F4.Hz., B4.Hz., F5.Hz., B5.Hz.)) %>%
    dplyr::rename(Time_s = time.s.,
                  F1_Hz = F1.Hz.,
                  F2_Hz = F2.Hz.,
                  F3_Hz = F3.Hz.) %>%
    dplyr::mutate(F1_Hz = ifelse(F1_Hz == 0, NA, F1_Hz),
                  F2_Hz = ifelse(F2_Hz == 0, NA, F2_Hz),
                  F3_Hz = ifelse(F3_Hz == 0, NA, F3_Hz)) %>%
    dplyr::mutate(F1_Hz = as.numeric(F1_Hz),
                  F2_Hz = as.numeric(F2_Hz),
                  F3_Hz = suppressWarnings(as.numeric(F3_Hz)),
                  Time_ms = Time_s / 1000,
                  F1_kHz = F1_Hz / 1000,
                  F2_kHz = F2_Hz / 1000,
                  F3_kHz = F3_Hz / 1000) %>%
    dplyr::select(!Time_s) %>%
    dplyr::relocate(Time_ms, .before = F1_Hz) %>%
    cbind(.,Pitch_PRAAT)
  
  c <- 2
  while(c < NROW(Formants_PRAAT)){
    Formants_PRAAT$F1_Hz[c] <- ifelse(is.na(Formants_PRAAT$F1_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F1_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F1_Hz[c])
    Formants_PRAAT$F2_Hz[c] <- ifelse(is.na(Formants_PRAAT$F2_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F2_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F2_Hz[c])
    c <- c + 1
  }
  rm(c)
  
  Formants_PRAAT <- Formants_PRAAT %>%
    dplyr::filter(!is.na(Pitch)) %>%
    dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                  F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5) %>%
    dplyr::filter(F1_mad == FALSE & F2_mad == FALSE) %>%
    dplyr::mutate(mDist = mahalanobis(cbind(.$F1_Hz, .$F2_Hz),
                                      colMeans(cbind(.$F1_Hz, .$F2_Hz)),
                                      cov = cov(cbind(.$F1_Hz, .$F2_Hz))),
                  mDist_sd = abs(scale(mDist,center = T))) %>%
    dplyr::filter(mDist_sd < 2) %>%
    dplyr::select(!c(F1_mad, F2_mad, mDist, mDist_sd)) %>%
    dplyr::mutate(F1_z = scale(F1_Hz, center = TRUE),
                  F2_z = scale(F2_Hz, center = TRUE),
                  F3_z = scale(F3_Hz, center = TRUE),
                  F1_b = emuR::bark(F1_Hz),
                  F2_b = emuR::bark(F2_Hz),
                  F3_b = emuR::bark(F3_Hz))
  
  rm(Pitch_PRAAT)
  
  
## Corner Dispersion ----
  wedge <- vowelData %>%
    dplyr::group_by(Vowel) %>%
    dplyr::summarize(mean_F1 = mean(F1_tempMid),
              mean_F2 = mean(F2_tempMid),
              mean_F1_z = mean(F1_z_tempMid),
              mean_F2_z = mean(F2_z_tempMid),
              mean_F1_b = mean(F1_b_tempMid),
              mean_F2_b = mean(F2_b_tempMid)) %>%
    dplyr::filter(Vowel == "v")
    
  corner_dis <- vowelData %>%
    dplyr::filter(Vowel != "v") %>%
    dplyr::group_by(Vowel) %>%
    dplyr::summarize(mean_F1 = mean(F1_tempMid),
              mean_F2 = mean(F2_tempMid),
              mean_F1_z = mean(F1_z_tempMid),
              mean_F2_z = mean(F2_z_tempMid),
              mean_F1_b = mean(F1_b_tempMid),
              mean_F2_b = mean(F2_b_tempMid)) %>%
    dplyr::mutate(Vowel_ED = sqrt((mean_F1-wedge$mean_F1)^2 + (mean_F2-wedge$mean_F2)^2),
                  Vowel_ED_z = sqrt((mean_F1_z-wedge$mean_F1_z)^2 + (mean_F2_z-wedge$mean_F2_z)^2),
                  Vowel_ED_b = sqrt((mean_F1_b-wedge$mean_F1_b)^2 + (mean_F2_b-wedge$mean_F2_b)^2))

    
# Plot Corner Dispersion
      # Changing to IPA symbols
      corner_dis <- corner_dis %>%
        dplyr::mutate(Vowel = dplyr::case_when(
          Vowel == "ae" ~ "æ",
          TRUE ~ Vowel
        ))
      
      wedge <- wedge %>%
        dplyr::mutate(Vowel = case_when(
          Vowel == "v" ~ "ʌ",
          TRUE ~ Vowel
        ))
      
      CDplot <- ggplot(aes(x=F2_b,
                           y=F1_b),
                       data = Formants_PRAAT,
                       inherit.aes = FALSE) + 
      geom_point(shape = 21,
                 alpha = formantAlpha,
                 color = formantColor) + 
      geom_line(aes(x = mean_F2_b,
                    y = mean_F1_b),
                data = corner_dis %>%
                  dplyr::select(Vowel:mean_F2_b) %>%
                  dplyr::filter(Vowel == "i") %>%
                  rbind(.,wedge),
                color = lineColor,
                size = 1.5,
                alpha = lineAlpha) +
      geom_line(aes(x = mean_F2_b,
                    y = mean_F1_b),
                data = corner_dis %>%
                  dplyr::select(Vowel:mean_F2_b) %>%
                  dplyr::filter(Vowel == "a") %>%
                  rbind(.,wedge),
                color = lineColor,
                size = 1.5,
                alpha = lineAlpha) +
      geom_line(aes(x = mean_F2_b,
                    y = mean_F1_b),
                data = corner_dis %>%
                  dplyr::select(Vowel:mean_F2_b) %>%
                  dplyr::filter(Vowel == "æ") %>%
                  rbind(.,wedge),
                color = lineColor,
                size = 1.5,
                alpha = lineAlpha) +
      geom_line(aes(x = mean_F2_b,
                    y = mean_F1_b),
                data = corner_dis %>%
                  dplyr::select(Vowel:mean_F2_b) %>%
                  dplyr::filter(Vowel == "u") %>%
                  rbind(.,wedge),
                color = lineColor,
                size = 1.5,
                alpha = lineAlpha) +
      geom_point(aes(x = mean_F2_b,
                     y = mean_F1_b,
                     color = Vowel),
                 data = corner_dis %>%
                  dplyr::select(Vowel:mean_F2_b) %>%
                  rbind(.,wedge),
                 inherit.aes = FALSE,
                 size = 5) +
      scale_y_reverse() +
      scale_x_reverse() +
      theme_classic() + labs(title = paste("Corner Dispersion")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1) +
          scale_color_manual(values = c("a" = "#1AAD77",
                                        "æ" = "#1279B5",
                                        "i" = "#FFBF00",
                                        "u" = "#FD7853",
                                        "ʌ" = "#BF3178"))
    CDplot

    
      rm(corner_dis, wedge)
      
## Vowel Space Area ----
  VSA_coords <- vowelData %>%
    dplyr::filter(Vowel != "v") %>%
    dplyr::group_by(Vowel) %>%
    dplyr::summarize(mean_F1 = mean(F1_tempMid),
              mean_F2 = mean(F2_tempMid),
              mean_F1_z = mean(F1_z_tempMid),
              mean_F2_z = mean(F2_z_tempMid),
              mean_F1_b = mean(F1_b_tempMid),
              mean_F2_b = mean(F2_b_tempMid)) 
  
### Plotting VSA
    VSA_coords <- VSA_coords %>%
        dplyr::mutate(Vowel = case_when(
          Vowel == "ae" ~ "æ",
          TRUE ~ Vowel
        ))
    
    VSAplot <- ggplot(aes(x = F2_b,
                          y = F1_b),
                      data = Formants_PRAAT,
                      inherit.aes = FALSE) + 
      geom_point(shape = 21,
                 alpha = formantAlpha,
                 color = formantColor) + 
      geom_polygon(aes(x = mean_F2_b,
                       y = mean_F1_b),
                   data = VSA_coords,
                   alpha = lineAlpha,
                   color = lineColor,
                   fill=NA,
                   size = 1.5) +
      geom_point(aes(x = mean_F2_b,
                     y = mean_F1_b,
                     color = Vowel),
                 data = VSA_coords,
                 inherit.aes = FALSE,
                 size = 5) +
      scale_y_reverse() +
      scale_x_reverse() +
      guides(color = FALSE) +
      theme_classic() + labs(title = "VSA") + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1) +
                scale_color_manual(values = c("a" = "#1AAD77",
                                        "æ" = "#1279B5",
                                        "i" = "#FFBF00",
                                        "u" = "#FD7853"))
`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
    VSAplot

  
  rm(VSA_coords)
  
## Hull ----
### Plotting Hull
      convexCoords <- Formants_PRAAT %>%
        dplyr::select(F1_b, F2_b) %>%
        as.matrix() %>%
        grDevices::chull()
      convex <- Formants_PRAAT %>%
        slice(convexCoords)

      hullPlot <- ggplot(aes(F2_b, F1_b),
                         data = Formants_PRAAT) +
        geom_point(shape = 21,
                 alpha = formantAlpha,
                 color = formantColor) +
        geom_polygon(data = convex,
                     alpha = .5,
                     color = "#1279B5",
                     fill = NA,
                     size = 1.5) +
        scale_y_reverse() +
        scale_x_reverse() +
        theme_classic() + labs(title = expression("VSA"[Hull])) +
                                 xlab("F2 (Bark)") +
                                 ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1)
      hullPlot

    
  
## Vowel Space Density ----

# Bark Normalized Density ----
# selecting the bandwidth
H_hpi <- ks::Hpi(x = Formants_PRAAT[,c("F2_b","F1_b")], pilot = "samse", pre = "scale", binned = T)

# compute 2d kde
k <- kde(x = Formants_PRAAT[,c("F2_b","F1_b")],
         H = H_hpi,
         binned = T,
         gridsize = 250)

#density <- k[["estimate"]]

# Before we can plot the density estimate we need to melt it into long format
mat.melted <- data.table::melt(k$estimate)
The melt generic in data.table has been passed a matrix and will attempt to redirect to the relevant reshape2 method; please note that reshape2 is deprecated, and this redirection is now deprecated as well. To continue using melt methods from reshape2 while both libraries are attached, e.g. melt.list, you can prepend the namespace like reshape2::melt(k$estimate). In the next version, this warning will become an error.
names(mat.melted) <- c("x", "y", "density")

# We need to add two more colums to preserve the axes units
mat.melted$F2.b <- rep(k$eval.points[[1]], times = nrow(k$estimate))
mat.melted$F1.b <- rep(k$eval.points[[2]], each = nrow(k$estimate))
mat.melted$density <- scales::rescale(mat.melted$density, to = c(0, 1))

# VSD - 25
nVSD_25 <- mat.melted %>%
  dplyr::filter(density > .25) %>%
  dplyr::select(F2.b,F1.b, density) %>%
  dplyr::rename(Density = density)

convexCoords <- nVSD_25 %>%
  dplyr::select(F2.b, F1.b) %>%
  as.matrix() %>%
  #grDevices::xy.coords() %>%
  grDevices::chull()
nconvex_25 <- nVSD_25 %>%
  slice(convexCoords)

# VSD - 75
nVSD_75 <- mat.melted %>%
  dplyr::filter(density > .75) %>%
  dplyr::select(F2.b,F1.b, density) %>%
  dplyr::rename(Density = density)

convexCoords <- nVSD_75 %>%
  dplyr::select(F2.b, F1.b) %>%
  as.matrix() %>%
  grDevices::chull()
nconvex_75 <- nVSD_75 %>%
  slice(convexCoords)

# Plotting Z Normalized VSD 
    rf <- colorRampPalette(rev(RColorBrewer::brewer.pal(11, "Spectral")))
    r <- rf(32)
    
    plotData <- mat.melted %>%
                        dplyr::rename(Density = density) %>%
                        dplyr::mutate(VSDlabel = dplyr::case_when(
                          Density < .25 ~ "none",
                          Density > .25 && Density < .75 ~ "VSD25",
                          TRUE ~ "VSD75"
                        ))
geom.text.size <- 2
    VSDplot <- ggplot(data = plotData,
                      aes(x = F2.b,
                          y = F1.b,
                          fill = Density)) + 
      geom_tile() + 
      scale_fill_viridis_c() +
      scale_x_reverse(expand = c(0, 0), 
                      breaks = round(seq(min(mat.melted$F2.b), 
                                         max(mat.melted$F2.b), by = 2))) +
      scale_y_reverse(expand = c(0, 0),
                      breaks = round(seq(min(mat.melted$F1.b),
                                         max(mat.melted$F1.b), by = 2))) + 
      ylab("F1 (Bark)") + xlab("F2 (Bark)") +
      labs(title = "VSD") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1) +
      geom_polygon(data = nconvex_25, alpha = lineAlpha, color = lineColor, size = 1.5, fill = NA, linetype = 2) +
      geom_polygon(data = nconvex_75, alpha = lineAlpha, color = lineColor, size = 1.5, fill = NA, linetype = 1) +
    # VSD 25 Label
      annotate(geom = "curve",
               x = 6.9, y = 1.7+.5,
               xend = 8.5, yend = 3.5,
               curvature = -.3,
               arrow = arrow(length = unit(2, "mm")),
               color = "white") +
      annotate(geom = "text",
               x = 7.5, y = 1.7,
               label = deparse(bquote(VSD[25])),
               hjust = "center",
               color = "white",
               parse=TRUE) +
    # VSD 75 Label
      annotate(geom = "curve",
               x = 7.5, y = 7.5-.5,
               xend = 11.35, yend = 5.5,
               curvature = .3,
               arrow = arrow(length = unit(2, "mm")),
               color = "white") +
      annotate(geom = "text",
               x = 7, y = 7.5,
               label = deparse(bquote(VSD[75])),
               hjust = "center",
               color = "white",
               parse = TRUE)
     VSDplot


# Combined Plot
     
     row1 <- VSAplot + CDplot +
        patchwork::plot_layout(guides = 'collect',
                         ncol = 2) & theme(legend.position = 'right')
     row2 <- hullPlot + VSDplot +
        patchwork::plot_layout(guides = 'collect',
                         ncol = 2) & theme(legend.position = 'right')
     
     measuresPlot <- row1 / row2 + patchwork::plot_layout(heights = c(1/2, 1/2), byrow = FALSE)
     measuresPlot
     
     rm(row1, row2)

ggsave(filename = "Plots/Measures.png",
       plot = measuresPlot,
       height = 5.5,
       width = 6,
       scale = .8)

Filtering Process

formantAlpha <- .20
myPal <- c("#1279B5","#2D2D37")

Pitch_PRAAT <- list.files(path = paste("Prepped Data/Example Data/", sep = ""), 
                              pattern = ".Pitch", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = F) %>%
    dplyr::rename(Pitch = V1) %>%
    dplyr::mutate(Pitch = gsub("--undefined--",NA,Pitch),
                  Pitch = as.numeric(Pitch))

Formants_PRAAT <- list.files(path = paste("Prepped Data/Example Data/", sep = ""), 
                              pattern = "_Formant", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = T) %>%
    dplyr::select(!c(nformants, B1.Hz., B2.Hz., B3.Hz., F4.Hz., B4.Hz., F5.Hz., B5.Hz.)) %>%
    dplyr::rename(Time_s = time.s.,
                  F1_Hz = F1.Hz.,
                  F2_Hz = F2.Hz.,
                  F3_Hz = F3.Hz.) %>%
    dplyr::mutate(F1_Hz = ifelse(F1_Hz == 0, NA, F1_Hz),
                  F2_Hz = ifelse(F2_Hz == 0, NA, F2_Hz),
                  F3_Hz = ifelse(F3_Hz == 0, NA, F3_Hz)) %>%
    dplyr::mutate(F1_Hz = as.numeric(F1_Hz),
                  F2_Hz = as.numeric(F2_Hz),
                  F3_Hz = suppressWarnings(as.numeric(F3_Hz)),
                  Time_ms = Time_s / 1000,
                  F1_kHz = F1_Hz / 1000,
                  F2_kHz = F2_Hz / 1000,
                  F3_kHz = F3_Hz / 1000,
                  F1_b = emuR::bark(F1_Hz),
                  F2_b = emuR::bark(F2_Hz),
                  F3_b = emuR::bark(F3_Hz)) %>%
    dplyr::select(!Time_s) %>%
    dplyr::relocate(Time_ms, .before = F1_Hz) %>%
    cbind(.,Pitch_PRAAT)
  
  c <- 2
  while(c < NROW(Formants_PRAAT)){
    Formants_PRAAT$F1_Hz[c] <- ifelse(is.na(Formants_PRAAT$F1_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F1_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F1_Hz[c])
    Formants_PRAAT$F2_Hz[c] <- ifelse(is.na(Formants_PRAAT$F2_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F2_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F2_Hz[c])
    c <- c + 1
  }
  rm(c)
  
  # Raw Formants ----
  f1 <- ggplot(aes(x=F2_b,
                   y=F1_b),
               data = Formants_PRAAT) + 
      geom_point(shape = 21, color = myPal[2]) +
      scale_y_reverse(limits = c(16,0)) +
      scale_x_reverse(limits = c(19,3)) +
      scale_color_manual(values = myPal) +
      theme_classic() + labs(title = paste("Raw Formant\nValues")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1,
            legend.title = element_blank(),
            legend.text = element_text(size=12))
    
# Step #1: Voiced Segments ----
    plotData <- Formants_PRAAT %>%
                   dplyr::mutate(isOutlier = case_when(
                     is.na(Pitch) ~ "Removed",
                     TRUE ~ "Retained"
                   ))
    f2 <- ggplot(data = plotData,
                 aes(x = F2_b,
                     y = F1_b,
                     color = isOutlier)) + 
      geom_point(shape = 21, data = plotData %>%
                   dplyr::filter(isOutlier == "Removed")) +
      geom_point(shape = 21, data = plotData %>%
             dplyr::filter(isOutlier == "Retained")) +
      scale_y_reverse(limits = c(16,0)) +
      scale_x_reverse(limits = c(19,3)) +
      scale_color_manual(values = myPal) +
      theme_classic() + labs(title = paste("Voiced Segments")) +
      xlab("F2 (Bark)") +
      ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1,
            legend.title = element_blank(),
            legend.text = element_text(size=12))
    
# Step 2: MAD ----
    plotData <- Formants_PRAAT %>%
      dplyr::filter(!is.na(Pitch)) %>%
      dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                    F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5,
                    isOutlier = case_when(
                      F1_mad == TRUE | F2_mad == TRUE ~ "Removed",
                      TRUE ~ "Retained"
               ))
    
    f3 <- ggplot(data = plotData,
                 aes(x = F2_b,
                     y = F1_b,
                     color = isOutlier)) + 
      geom_point(shape = 21, data = plotData %>%
                   dplyr::filter(isOutlier == "Removed")) +
      geom_point(shape = 21, data = plotData %>%
             dplyr::filter(isOutlier == "Retained")) +
      scale_y_reverse(limits = c(16,0)) +
      scale_x_reverse(limits = c(19,3)) +
      scale_color_manual(values = myPal) +
      theme_classic() +
      labs(title = paste("Median Absolute\nDeviation")) +
      xlab("F2 (Bark)") +
      ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1,
            legend.title = element_blank(),
            legend.text = element_text(size=12))
    
# Step 3: Mahalanhobis Distance ----
  plotData <- Formants_PRAAT %>%
      dplyr::filter(!is.na(Pitch)) %>%
      dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                    F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5) %>%
      dplyr::filter(F1_mad == FALSE & F2_mad == FALSE) %>%
      dplyr::mutate(mDist = mahalanobis(cbind(.$F1_Hz, .$F2_Hz),
                                      colMeans(cbind(.$F1_Hz, .$F2_Hz)),
                                      cov = cov(cbind(.$F1_Hz, .$F2_Hz))),
                  mDist_sd = abs(scale(mDist,center = T)),
                  isOutlier = case_when(
                    mDist_sd < 2 ~ "Retained",
                    TRUE ~ "Removed"
                  ))
    
    f4 <- ggplot(data = plotData,
                 aes(x = F2_b,
                     y = F1_b,
                     color = isOutlier)) + 
      geom_point(shape = 21, data = plotData %>%
                   dplyr::filter(isOutlier == "Removed")) +
      geom_point(shape = 21, data = plotData %>%
             dplyr::filter(isOutlier == "Retained")) +
      scale_y_reverse(limits = c(16,0)) +
      scale_x_reverse(limits = c(19,3)) +
      scale_color_manual(values = myPal) +
      theme_classic() + labs(title = paste("Mahalanobis\nDistance")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1,
            legend.title = element_blank(),
            legend.text = element_text(size=12))
    
# Final Formants ----
    plotData <- Formants_PRAAT %>%
    dplyr::filter(!is.na(Pitch)) %>%
    dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                  F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5) %>%
    dplyr::filter(F1_mad == FALSE & F2_mad == FALSE) %>%
    dplyr::mutate(mDist = mahalanobis(cbind(.$F1_Hz, .$F2_Hz),
                                      colMeans(cbind(.$F1_Hz, .$F2_Hz)),
                                      cov = cov(cbind(.$F1_Hz, .$F2_Hz))),
                  mDist_sd = abs(scale(mDist,center = T))) %>%
    dplyr::filter(mDist_sd < 2)
    
    f5 <- ggplot(aes(x=F2_b,
                     y=F1_b),
                       data = plotData,
                       inherit.aes = FALSE) + 
      geom_point(shape = 21, color = myPal[2]) + 
      scale_y_reverse(limits = c(16,0)) +
      scale_x_reverse(limits = c(19,3)) +
      theme_classic() + labs(title = paste("Final Formant\nTrajectories")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1, legend.title = element_blank())
    
# Comibing plots
    filteredPlot <- f1 + f2 + f3 + f4 + f5 + patchwork::guide_area() +
      patchwork::plot_layout(guides = 'collect',
                         ncol = 3) +
      patchwork::plot_annotation(tag_levels = 'A')
    filteredPlot
    
    ggsave(plot = filteredPlot, "Plots/Filtered Formants.png",
           height = 6,
           width = 8,
           units = "in",
           scale = .9)

NA

OT vs. VAS

plotData_Int <- AcousticData %>%
  dplyr::filter(!grepl("_rel", Speaker)) %>%
  dplyr::group_by(Speaker) %>%
  dplyr::mutate(segMin = base::min(VAS, transAcc),
                segMax = base::max(VAS, transAcc),
                ratingAvg = mean(VAS, transAcc, na.rm = T),
                Speaker = as.factor(Speaker),
                Etiology = case_when(
                  Etiology == "Ataxic" ~ "Ataxia",
                  TRUE ~ as.character(Etiology)
                ),
                Etiology = as.factor(Etiology)) %>%
  arrange(segMax)

my_pal <- c("#f26430", "#272D2D","#256eff")
# With a bit more style
plot_Int <- ggplot(plotData_Int) +
  geom_segment(aes(x = fct_inorder(Speaker),
                   xend = Speaker,
                   y = segMin,
                   yend = segMax,
                   color = Etiology)) +
  geom_point(aes(x = Speaker,
                 y = VAS,
                 color = Etiology),
             #color = my_pal[1],
             size = 3,
             shape = 19) +
  geom_point(aes(x = Speaker,
                 y = transAcc,
                 color = Etiology),
             #color = my_pal[2],
             size = 3,
             shape = 15) +
  coord_flip()+
  theme_classic() +
  theme(
    legend.position = "none",
    panel.border = element_blank(),
  ) +
  xlab("") +
  ylab("Speech Intelligibility") +
  ggtitle("Speech Intelligibility") +
  ylim(c(0,100))


myPal <- c("#1AAD77", "#1279B5", "#FFBF00", "#FD7853", "#BF3178")
myShapes <- c(16, 18, 17, 15)

OT_VASscatter <- ggplot(plotData_Int,
                  aes(x = VAS,
                      y = transAcc,
                      color = Etiology,
                      shape = Etiology,
                      linetype = Etiology)) +
  geom_point() +
  geom_smooth(method = "lm", se = F) +
  geom_abline(intercept = 0, slope = 1) +
  coord_cartesian(xlim = c(0,100), ylim = c(0,100)) +
  labs(x = "Intelligibility (VAS)", y = "Intelligibility (OT)") +
  scale_color_manual(values = myPal) +
  scale_shape_manual(values = myShapes) +
  theme_classic() +
  theme(aspect.ratio=1,
        legend.position="right")


ggsave(filename = "Plots/OT and VAS Scatterplot.png",
       plot = OT_VASscatter,
       height = 3.25,
       width = 4,
       units = "in",
       scale = 1)

rm(scatter1, scatter2, combinedScatter)

Model Scatterplots

modelFigureData <- AcousticData %>%
  dplyr::filter(!grepl("_rel",Speaker)) %>%
  dplyr::select(Speaker, Etiology, Sex, VSA_b, vowel_ED_b, Hull_b, Hull_bVSD_25, Hull_bVSD_75, VAS, transAcc) %>%
  dplyr::mutate(Speaker = as.factor(Speaker),
                Etiology = as.factor(Etiology),
                Sex = as.factor(Sex)) %>%
  tidyr::pivot_longer(cols = VAS:transAcc, names_to = "IntType", values_to = "Int") %>%
  dplyr::mutate(IntType = case_when(
    IntType == "transAcc" ~ "OT",
    TRUE ~ "VAS"
  ),
                IntType = as.factor(IntType))

ylabel <- "Intelligibility"
myPal <- c("#2D2D37", "#1279B5")
myPalShape <- c(19, 1)

VSA <- modelFigureData %>%
  ggplot() +
  aes(x = VSA_b,
      y = Int,
      color = IntType,
      shape = IntType,
      linetype = IntType) +
  geom_point() +
  geom_smooth(method = "lm", se = T, fill = "light grey") +
  geom_smooth(method = "lm", se = F) +
  xlab(expression("VSA (Bark"^2*")")) +
  ylab(ylabel) +
  coord_cartesian(ylim = c(0,100)) +
  theme_classic() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        aspect.ratio=1) +
  scale_color_manual(values = myPal) +
  scale_shape_manual(values = myPalShape) +
  labs(color="Intelligibility Type",
       shape = "Intelligibility Type",
       linetype = "Intelligibility Type")

disp <- modelFigureData %>%
  ggplot() +
  aes(x = vowel_ED_b,
      y = Int,
      color = IntType,
      shape = IntType,
      linetype = IntType) +
  geom_point() +
  geom_smooth(method = "lm", se = T, fill = "light grey") +
  geom_smooth(method = "lm", se = F) +
  xlab("Corner Dispersion (Bark)") +
  ylab(ylabel) +
  coord_cartesian(ylim = c(0,100)) +
  theme_classic() +
  theme(aspect.ratio=1) +
  scale_color_manual(values = myPal) +
  scale_shape_manual(values = myPalShape) +
  labs(color="Intelligibility Type",
       shape = "Intelligibility Type",
       linetype = "Intelligibility Type")

Hull <- modelFigureData %>%
  ggplot() +
  aes(x = Hull_b,
      y = Int,
      color = IntType,
      shape = IntType,
      linetype = IntType) +
  geom_point() +
  geom_smooth(method = "lm", se = T, fill = "light grey") +
  geom_smooth(method = "lm", se = F) +
  xlab(expression("VSA"[Hull]*" (Bark"^2*")")) +
  ylab(ylabel) +
  coord_cartesian(ylim = c(0,100)) +
  theme_classic() +
  theme(aspect.ratio=1) + theme(legend.position = "none") +
  scale_color_manual(values = myPal) +
  scale_shape_manual(values = myPalShape) +
  labs(color="Intelligibility Type",
       shape = "Intelligibility Type",
       linetype = "Intelligibility Type")

vsd25 <- modelFigureData %>%
  ggplot() +
  aes(x = Hull_bVSD_25,
      y = Int,
      color = IntType,
      shape = IntType,
      linetype = IntType) +
  geom_point() +
  geom_smooth(method = "lm", se = T, fill = "light grey") +
  geom_smooth(method = "lm", se = F) +
  xlab(expression("VSD"[25]*" (Bark"^2*")")) +
  ylab(ylabel) +
  coord_cartesian(ylim = c(0,100)) +
  theme_classic() +
  theme(aspect.ratio=1) + theme(legend.position = "none") +
  scale_color_manual(values = myPal) +
  scale_shape_manual(values = myPalShape) +
  labs(color="Intelligibility Type",
       shape = "Intelligibility Type",
       linetype = "Intelligibility Type")

vsd75 <- modelFigureData %>%
  ggplot() +
  aes(x = Hull_bVSD_75,
      y = Int,
      color = IntType,
      shape = IntType,
      linetype = IntType) +
  geom_point() +
  geom_smooth(method = "lm", se = T, fill = "light grey") +
  geom_smooth(method = "lm", se = F) +
  xlab(expression("VSD"[75]*" (Bark"^2*")")) +
  ylab(ylabel) +
  coord_cartesian(ylim = c(0,100)) +
  theme_classic() +
  theme(aspect.ratio=1) + theme(legend.position = "none") +
  scale_color_manual(values = myPal) +
  scale_shape_manual(values = myPalShape) +
  labs(color="Intelligibility Type",
       shape = "Intelligibility Type",
       linetype = "Intelligibility Type")

# Creating OT Scatterplot Figure

scatter <- VSA  + disp + patchwork::guide_area() + Hull + vsd25 + vsd75 +
  patchwork::plot_layout(guides = 'collect',
                         ncol = 3) & theme(legend.position = "right")
scatter 

ggsave("Plots/ModelFigure.png", scatter,
       height = 4,
       width = 6,
       units = "in",
       scale = 1.1)

Filtering at Different Levels

text_x <- 12.5
text_y <- 8.5
xlims <- c(16,5)
ylims <- c(9,1)
# Hull - 2 SD ----
Pitch_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = ".Pitch", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = F) %>%
    dplyr::rename(Pitch = V1) %>%
    dplyr::mutate(Pitch = gsub("--undefined--",NA,Pitch),
                  Pitch = as.numeric(Pitch))

Formants_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = "_Formant", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = T) %>%
    dplyr::select(!c(nformants, B1.Hz., B2.Hz., B3.Hz., F4.Hz., B4.Hz., F5.Hz., B5.Hz.)) %>%
    dplyr::rename(Time_s = time.s.,
                  F1_Hz = F1.Hz.,
                  F2_Hz = F2.Hz.,
                  F3_Hz = F3.Hz.) %>%
    dplyr::mutate(F1_Hz = ifelse(F1_Hz == 0, NA, F1_Hz),
                  F2_Hz = ifelse(F2_Hz == 0, NA, F2_Hz),
                  F3_Hz = ifelse(F3_Hz == 0, NA, F3_Hz)) %>%
    dplyr::mutate(F1_Hz = as.numeric(F1_Hz),
                  F2_Hz = as.numeric(F2_Hz),
                  F3_Hz = suppressWarnings(as.numeric(F3_Hz)),
                  Time_ms = Time_s / 1000,
                  F1_kHz = F1_Hz / 1000,
                  F2_kHz = F2_Hz / 1000,
                  F3_kHz = F3_Hz / 1000,
                  F1_b = emuR::bark(F1_Hz),
                  F2_b = emuR::bark(F2_Hz),
                  F3_b = emuR::bark(F3_Hz)) %>%
    dplyr::select(!Time_s) %>%
    dplyr::relocate(Time_ms, .before = F1_Hz) %>%
    cbind(.,Pitch_PRAAT) %>%
    dplyr::filter(!is.na(Pitch)) %>%
    dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                  F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5) %>%
    dplyr::filter(F1_mad == FALSE & F2_mad == FALSE) %>%
    dplyr::mutate(mDist = mahalanobis(cbind(.$F1_Hz, .$F2_Hz),
                                      colMeans(cbind(.$F1_Hz, .$F2_Hz)),
                                      cov = cov(cbind(.$F1_Hz, .$F2_Hz))),
                  mDist_sd = abs(scale(mDist,center = T))) %>%
    #dplyr::mutate(mDistOutlier = (stats::pchisq(mDist, df=1, lower.tail=FALSE)) < .001) %>%
    dplyr::filter(mDist_sd < 2)
  
  c <- 2
  while(c < NROW(Formants_PRAAT)){
    Formants_PRAAT$F1_Hz[c] <- ifelse(is.na(Formants_PRAAT$F1_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F1_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F1_Hz[c])
    Formants_PRAAT$F2_Hz[c] <- ifelse(is.na(Formants_PRAAT$F2_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F2_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F2_Hz[c])
    c <- c + 1
  }
  rm(c)
  
    Hull_b <- cHull(Formants_PRAAT$F1_b, Formants_PRAAT$F2_b)
### Plotting Hull
      convexCoords <- Formants_PRAAT %>%
        dplyr::select(F1_b, F2_b) %>%
        as.matrix() %>%
        grDevices::chull()
      convex <- Formants_PRAAT %>%
        slice(convexCoords)

      hullPlot_2 <- ggplot(aes(F2_b, F1_b),
                         data = Formants_PRAAT) +
        geom_point(shape = 21) +
        geom_polygon(data = convex,
                     alpha = .5,
                     color = "#1279B5",
                     fill = NA,
                     size = 1.5) +
        annotate("text", x = text_x, y = text_y, label = paste("Hull =",round(Hull_b,2))) +
        scale_y_reverse() +
        scale_x_reverse() +
        xlim(xlims) +
        ylim(ylims) +
        theme_classic() + labs(title = paste("2 SD")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
        theme(plot.title = element_text(hjust = 0.5),
              aspect.ratio = 1)
Scale for 'x' is already present. Adding another scale for 'x', which will replace the
existing scale.
Scale for 'y' is already present. Adding another scale for 'y', which will replace the
existing scale.
      hullPlot_2

      
# Hull - 2.5 SD ----
Pitch_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = ".Pitch", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = F) %>%
    dplyr::rename(Pitch = V1) %>%
    dplyr::mutate(Pitch = gsub("--undefined--",NA,Pitch),
                  Pitch = as.numeric(Pitch))

Formants_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = "_Formant", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = T) %>%
    dplyr::select(!c(nformants, B1.Hz., B2.Hz., B3.Hz., F4.Hz., B4.Hz., F5.Hz., B5.Hz.)) %>%
    dplyr::rename(Time_s = time.s.,
                  F1_Hz = F1.Hz.,
                  F2_Hz = F2.Hz.,
                  F3_Hz = F3.Hz.) %>%
    dplyr::mutate(F1_Hz = ifelse(F1_Hz == 0, NA, F1_Hz),
                  F2_Hz = ifelse(F2_Hz == 0, NA, F2_Hz),
                  F3_Hz = ifelse(F3_Hz == 0, NA, F3_Hz)) %>%
    dplyr::mutate(F1_Hz = as.numeric(F1_Hz),
                  F2_Hz = as.numeric(F2_Hz),
                  F3_Hz = suppressWarnings(as.numeric(F3_Hz)),
                  Time_ms = Time_s / 1000,
                  F1_kHz = F1_Hz / 1000,
                  F2_kHz = F2_Hz / 1000,
                  F3_kHz = F3_Hz / 1000,
                  F1_b = emuR::bark(F1_Hz),
                  F2_b = emuR::bark(F2_Hz),
                  F3_b = emuR::bark(F3_Hz)) %>%
    dplyr::select(!Time_s) %>%
    dplyr::relocate(Time_ms, .before = F1_Hz) %>%
    cbind(.,Pitch_PRAAT) %>%
    dplyr::filter(!is.na(Pitch)) %>%
    dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                  F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5) %>%
    dplyr::filter(F1_mad == FALSE & F2_mad == FALSE) %>%
    dplyr::mutate(mDist = mahalanobis(cbind(.$F1_Hz, .$F2_Hz),
                                      colMeans(cbind(.$F1_Hz, .$F2_Hz)),
                                      cov = cov(cbind(.$F1_Hz, .$F2_Hz))),
                  mDist_sd = abs(scale(mDist,center = T))) %>%
    #dplyr::mutate(mDistOutlier = (stats::pchisq(mDist, df=1, lower.tail=FALSE)) < .001) %>%
    dplyr::filter(mDist_sd < 2.5)
  
  c <- 2
  while(c < NROW(Formants_PRAAT)){
    Formants_PRAAT$F1_Hz[c] <- ifelse(is.na(Formants_PRAAT$F1_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F1_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F1_Hz[c])
    Formants_PRAAT$F2_Hz[c] <- ifelse(is.na(Formants_PRAAT$F2_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F2_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F2_Hz[c])
    c <- c + 1
  }
  rm(c)
  
    Hull_b <- cHull(Formants_PRAAT$F1_b, Formants_PRAAT$F2_b)
### Plotting Hull
      convexCoords <- Formants_PRAAT %>%
        dplyr::select(F1_b, F2_b) %>%
        as.matrix() %>%
        grDevices::chull()
      convex <- Formants_PRAAT %>%
        slice(convexCoords)

      hullPlot_2.5 <- ggplot(aes(F2_b, F1_b),
                         data = Formants_PRAAT) +
        geom_point(shape = 21) +
        geom_polygon(data = convex,
                     alpha = .5,
                     color = "#1279B5",
                     fill = NA,
                     size = 1.5) +
        annotate("text", x = text_x, y = text_y, label = paste("Hull =",round(Hull_b,2))) +
        scale_y_reverse() +
        scale_x_reverse() +
        xlim(xlims) +
        ylim(ylims) +
        theme_classic() + labs(title = paste("2.5 SD")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
        theme(plot.title = element_text(hjust = 0.5),
              aspect.ratio = 1)
Scale for 'x' is already present. Adding another scale for 'x', which will replace the
existing scale.
Scale for 'y' is already present. Adding another scale for 'y', which will replace the
existing scale.
      hullPlot_2.5

      
# Hull - 3 SD ----
Pitch_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = ".Pitch", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = F) %>%
    dplyr::rename(Pitch = V1) %>%
    dplyr::mutate(Pitch = gsub("--undefined--",NA,Pitch),
                  Pitch = as.numeric(Pitch))

Formants_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = "_Formant", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = T) %>%
    dplyr::select(!c(nformants, B1.Hz., B2.Hz., B3.Hz., F4.Hz., B4.Hz., F5.Hz., B5.Hz.)) %>%
    dplyr::rename(Time_s = time.s.,
                  F1_Hz = F1.Hz.,
                  F2_Hz = F2.Hz.,
                  F3_Hz = F3.Hz.) %>%
    dplyr::mutate(F1_Hz = ifelse(F1_Hz == 0, NA, F1_Hz),
                  F2_Hz = ifelse(F2_Hz == 0, NA, F2_Hz),
                  F3_Hz = ifelse(F3_Hz == 0, NA, F3_Hz)) %>%
    dplyr::mutate(F1_Hz = as.numeric(F1_Hz),
                  F2_Hz = as.numeric(F2_Hz),
                  F3_Hz = suppressWarnings(as.numeric(F3_Hz)),
                  Time_ms = Time_s / 1000,
                  F1_kHz = F1_Hz / 1000,
                  F2_kHz = F2_Hz / 1000,
                  F3_kHz = F3_Hz / 1000,
                  F1_b = emuR::bark(F1_Hz),
                  F2_b = emuR::bark(F2_Hz),
                  F3_b = emuR::bark(F3_Hz)) %>%
    dplyr::select(!Time_s) %>%
    dplyr::relocate(Time_ms, .before = F1_Hz) %>%
    cbind(.,Pitch_PRAAT) %>%
    dplyr::filter(!is.na(Pitch)) %>%
    dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                  F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5) %>%
    dplyr::filter(F1_mad == FALSE & F2_mad == FALSE) %>%
    dplyr::mutate(mDist = mahalanobis(cbind(.$F1_Hz, .$F2_Hz),
                                      colMeans(cbind(.$F1_Hz, .$F2_Hz)),
                                      cov = cov(cbind(.$F1_Hz, .$F2_Hz))),
                  mDist_sd = abs(scale(mDist,center = T))) %>%
    #dplyr::mutate(mDistOutlier = (stats::pchisq(mDist, df=1, lower.tail=FALSE)) < .001) %>%
    dplyr::filter(mDist_sd < 3)
  
  c <- 2
  while(c < NROW(Formants_PRAAT)){
    Formants_PRAAT$F1_Hz[c] <- ifelse(is.na(Formants_PRAAT$F1_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F1_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F1_Hz[c])
    Formants_PRAAT$F2_Hz[c] <- ifelse(is.na(Formants_PRAAT$F2_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F2_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F2_Hz[c])
    c <- c + 1
  }
  rm(c)
  
    Hull_b <- cHull(Formants_PRAAT$F1_b, Formants_PRAAT$F2_b)
### Plotting Hull
      convexCoords <- Formants_PRAAT %>%
        dplyr::select(F1_b, F2_b) %>%
        as.matrix() %>%
        grDevices::chull()
      convex <- Formants_PRAAT %>%
        slice(convexCoords)

      hullPlot_3 <- ggplot(aes(F2_b, F1_b),
                         data = Formants_PRAAT) +
        geom_point(shape = 21) +
        geom_polygon(data = convex,
                     alpha = .5,
                     color = "#1279B5",
                     fill = NA,
                     size = 1.5) +
        annotate("text", x = text_x, y = text_y, label = paste("Hull =",round(Hull_b,2))) +
        scale_y_reverse() +
        scale_x_reverse() +
        xlim(xlims) +
        ylim(ylims) +
        theme_classic() + labs(title = paste("3 SD")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
        theme(plot.title = element_text(hjust = 0.5),
              aspect.ratio = 1)
Scale for 'x' is already present. Adding another scale for 'x', which will replace the
existing scale.
Scale for 'y' is already present. Adding another scale for 'y', which will replace the
existing scale.
      hullPlot_3

      
# Hull - 1.5 SD ----
Pitch_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = ".Pitch", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = F) %>%
    dplyr::rename(Pitch = V1) %>%
    dplyr::mutate(Pitch = gsub("--undefined--",NA,Pitch),
                  Pitch = as.numeric(Pitch))

Formants_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = "_Formant", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = T) %>%
    dplyr::select(!c(nformants, B1.Hz., B2.Hz., B3.Hz., F4.Hz., B4.Hz., F5.Hz., B5.Hz.)) %>%
    dplyr::rename(Time_s = time.s.,
                  F1_Hz = F1.Hz.,
                  F2_Hz = F2.Hz.,
                  F3_Hz = F3.Hz.) %>%
    dplyr::mutate(F1_Hz = ifelse(F1_Hz == 0, NA, F1_Hz),
                  F2_Hz = ifelse(F2_Hz == 0, NA, F2_Hz),
                  F3_Hz = ifelse(F3_Hz == 0, NA, F3_Hz)) %>%
    dplyr::mutate(F1_Hz = as.numeric(F1_Hz),
                  F2_Hz = as.numeric(F2_Hz),
                  F3_Hz = suppressWarnings(as.numeric(F3_Hz)),
                  Time_ms = Time_s / 1000,
                  F1_kHz = F1_Hz / 1000,
                  F2_kHz = F2_Hz / 1000,
                  F3_kHz = F3_Hz / 1000,
                  F1_b = emuR::bark(F1_Hz),
                  F2_b = emuR::bark(F2_Hz),
                  F3_b = emuR::bark(F3_Hz)) %>%
    dplyr::select(!Time_s) %>%
    dplyr::relocate(Time_ms, .before = F1_Hz) %>%
    cbind(.,Pitch_PRAAT) %>%
    dplyr::filter(!is.na(Pitch)) %>%
    dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                  F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5) %>%
    dplyr::filter(F1_mad == FALSE & F2_mad == FALSE) %>%
    dplyr::mutate(mDist = mahalanobis(cbind(.$F1_Hz, .$F2_Hz),
                                      colMeans(cbind(.$F1_Hz, .$F2_Hz)),
                                      cov = cov(cbind(.$F1_Hz, .$F2_Hz))),
                  mDist_sd = abs(scale(mDist,center = T))) %>%
    #dplyr::mutate(mDistOutlier = (stats::pchisq(mDist, df=1, lower.tail=FALSE)) < .001) %>%
    dplyr::filter(mDist_sd < 1.5)
  
  c <- 2
  while(c < NROW(Formants_PRAAT)){
    Formants_PRAAT$F1_Hz[c] <- ifelse(is.na(Formants_PRAAT$F1_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F1_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F1_Hz[c])
    Formants_PRAAT$F2_Hz[c] <- ifelse(is.na(Formants_PRAAT$F2_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F2_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F2_Hz[c])
    c <- c + 1
  }
  rm(c)
  
    Hull_b <- cHull(Formants_PRAAT$F1_b, Formants_PRAAT$F2_b)
### Plotting Hull
      convexCoords <- Formants_PRAAT %>%
        dplyr::select(F1_b, F2_b) %>%
        as.matrix() %>%
        grDevices::chull()
      convex <- Formants_PRAAT %>%
        slice(convexCoords)

      hullPlot_1.5 <- ggplot(aes(F2_b, F1_b),
                         data = Formants_PRAAT) +
        geom_point(shape = 21) +
        geom_polygon(data = convex,
                     alpha = .5,
                     color = "#1279B5",
                     fill = NA,
                     size = 1.5) +
        annotate("text", x = text_x, y = text_y, label = paste("Hull =",round(Hull_b,2))) +
        scale_y_reverse() +
        scale_x_reverse() +
        xlim(xlims) +
        ylim(ylims) +
        theme_classic() + labs(title = paste("1.5 SD")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
        theme(plot.title = element_text(hjust = 0.5),
              aspect.ratio = 1)
Scale for 'x' is already present. Adding another scale for 'x', which will replace the
existing scale.
Scale for 'y' is already present. Adding another scale for 'y', which will replace the
existing scale.
      hullPlot_1.5

      
# Combined ----
      ggpubr::ggarrange(hullPlot_1.5, hullPlot_2, hullPlot_2.5, hullPlot_3,
                        ncol = 4)
      ggsave(filename = "Plots/Hull at Different Filters.png",
             height = 3,
             width= 9,
             units = "in",
             scale = 1)

NA

Listener Demographic Information


ListenerDemo <- Listeners %>%
  furniture::table1(age, gender, race, ethnicity)
ListenerDemo

──────────────────────────────────────────────
──────────────────────────────────────────────

Speaker Demographics


SpeakerDemo <- AcousticData %>%
  dplyr::select(c(Speaker, Sex, Etiology))

Ages <- rio::import("Prepped Data/Speaker Ages.xlsx")

SpeakerDemo <- full_join(SpeakerDemo, Ages, by = "Speaker")

SpeakerDemoInfo <- SpeakerDemo %>%
  furniture::table1(Sex, Etiology, Age, na.rm = F)

SpeakerDemoInfo

SpeakerDemo %>%
  dplyr::summarize(mean_age = mean(Age, na.rm = T), age_sd = sd(Age, na.rm = T), age_range = range(Age, na.rm = T))
LS0tCnRpdGxlOiAiVm93ZWwgQWNvdXN0aWNzIGFzIFByZWRpY3RvcnMgb2YgU3BlZWNoIEludGVsbGlnaWJpbGl0eSBpbiBEeXNhcnRocmlhIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpUaGlzIGlzIHRoZSBjb2RlIGZvciB0aGUgc3RhdGlzdGljYWwgYW5hbHlzaXMgZm9yICJWb3dlbCBBY291c3RpY3MgYXMgUHJlZGljdG9ycyBvZiBTcGVlY2ggSW50ZWxsaWdpYmlsaXR5IGluIER5c2FydGhyaWEuIgoKIyBMb2FkaW5nIFBhY2thZ2VzClRoaXMgYmxvY2sgb2YgY29kZSBsb2FkcyBpbiB0aGUgcmVxdWlyZWQgcGFja2FnZXMgZm9yIHRoaXMgc2NyaXB0LiBJbiB0aGUgIydzLCBJIGhhdmUgcHJvdmlkZWQgdG8gdGhlIGNvZGUgdG8gaW5zdGFsbCBlYWNoIHBhY2thZ2UgaWYgbmVlZGVkLgpgYGB7cn0KCmxpYnJhcnkocmlvKSAjIGluc3RhbGwucGFja2FnZXMoJ3JpbycpCmxpYnJhcnkodGlkeXZlcnNlKSAjIGluc3RhbGwucGFja2FnZXMoJ3RpZHl2ZXJzZScpCmxpYnJhcnkoaXJyKSAjIGluc3RhbGwucGFja2FnZXMoJ2lycicpCmxpYnJhcnkocGVyZm9ybWFuY2UpICMgaW5zdGFsbC5wYWNrYWdlcygncGVyZm9ybWFuY2UnKQpsaWJyYXJ5KGNhcikgIyBpbnN0YWxsLnBhY2thZ2VzKCdjYXInKQpsaWJyYXJ5KGdncHVicikgIyBpbnN0YWxsLnBhY2thZ2VzKCdnZ3B1YnInKQpsaWJyYXJ5KEhtaXNjKSAjIGluc3RhbGwucGFja2FnZXMoJ0htaXNjJykKbGlicmFyeShnZ3JpZGdlcykgIyBpbnN0YWxsLnBhY2thZ2VzKCdnZ3JpZGdlcycpCmxpYnJhcnkoZnVybml0dXJlKSAjIGluc3RhbGwucGFja2FnZXMoJ2Z1cm5pdHVyZScpCmxpYnJhcnkoZ3QpICMgaW5zdGFsbC5wYWNrYWdlcygnZ3QnKQpsaWJyYXJ5KHBhdGNod29yaykgIyBpbnN0YWxsLnBhY2thZ2VzKCdwYXRjaHdvcmsnKQpsaWJyYXJ5KGtzKSAjIGluc3RhbGwucGFja2FnZXMoJ2tzJykKbGlicmFyeShlbXVSKSAjIGluc3RhbGwucGFja2FnZXMoJ2VtdVInKQpsaWJyYXJ5KG1zbFRvb2xzKSAjIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiQXVzdGluUlRob21wc29uL21zbFRvb2xzIikKCmBgYAoKIyBVcGxvYWQgRGF0YXNldHMKCmBgYHtyfQoKIyBSZWxpYWJpbGl0eSBEYXRhClJlbGlhYmlsaXR5IDwtIHJpbzo6aW1wb3J0KCJQcmVwcGVkIERhdGEvUmVsaWFiaWxpdHkgRGF0YS5jc3YiKQoKIyBTcGVha2VyIERhdGEKQWNvdXN0aWNEYXRhIDwtIHJpbzo6aW1wb3J0KCJQcmVwcGVkIERhdGEvQWNvdXN0aWNNZWFzdXJlcy5jc3YiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKCFncmVwbCgiX3JlbCIsIFNwZWFrZXIpKSAlPiUgIyBGaWx0ZXJzIG91dCByZWxpYWJpbGl0eSBkYXRhCiAgZHBseXI6OnNlbGVjdChjKFNwZWFrZXIsCiAgICAgICAgICAgICAgICAgIFNleCwKICAgICAgICAgICAgICAgICAgRXRpb2xvZ3ksCiAgICAgICAgICAgICAgICAgIHZvd2VsX0VEX2IsICMgQ29ybmVyIERpc3BlcnNpb24KICAgICAgICAgICAgICAgICAgVlNBX2IsICMgVHJhZGl0aW9uYWwgVlNBCiAgICAgICAgICAgICAgICAgIEh1bGxfYiwgIyBWU0EgSHVsbAogICAgICAgICAgICAgICAgICBIdWxsX2JWU0RfMjUsICMgVlNEIDI1CiAgICAgICAgICAgICAgICAgIEh1bGxfYlZTRF83NSwgIyBWU0QgNzUKICAgICAgICAgICAgICAgICAgVkFTLCAjIEludGVsbGlnaWJpbGl0eSAoVkFTKQogICAgICAgICAgICAgICAgICB0cmFuc0FjYykgIyBJbnRlbGxpZ2liaWxpdHkgKE9UKQogICAgICAgICAgICAgICAgKSAlPiUgCiAgIyBUaGUgZm9sbG93aW5nIGNvZGUgZW5zdXJlIGV0aW9sb2d5LCBzZXgsIGFuZCBzcGVha2VyIGFyZSBjb2RlZCBhcyBmYWN0b3JzCiAgZHBseXI6Om11dGF0ZShFdGlvbG9neSA9IGFzLmZhY3RvcihFdGlvbG9neSksCiAgICAgICAgICAgICAgICBTZXggPSBhcy5mYWN0b3IoU2V4KSwKICAgICAgICAgICAgICAgIFNwZWFrZXIgPSBhcy5mYWN0b3IoU3BlYWtlcikpCgojIExpc3RlbmVyIERhdGEKTGlzdGVuZXJzIDwtIHJpbzo6aW1wb3J0KCJQcmVwcGVkIERhdGEvTGlzdGVuZXJfRGVtb2dyYXBoaWNzLmNzdiIpICU+JQogIGRwbHlyOjpzZWxlY3QoIWMoU3RhcnREYXRlOnByb2xvZmljSUQsICMgcmVtb3ZlcyB1bndhbnRlZCBjb2x1bW5zCiAgICAgICAgICAgICAgICAgICBRMi40XzZfVEVYVCwKICAgICAgICAgICAgICAgICAgIFEzLjJfOF9URVhULAogICAgICAgICAgICAgICAgICAgQXVkaW9DaGVjazpFUDMpKSAlPiUgCiAgIyBUaGUgZm9sbG93IGNvZGUgY29ycmVjdHMgZm9yIHdoZW4gYSBsaXN0ZW5lciByZXBsaWVkICJPdGhlciIgaW5zdGVhZCBvZiB0aGUgQmlyYWNpYWwgb3IgTXVsdGlyYWNpYWwiIHJlc3BvbnNlCiAgZHBseXI6Om11dGF0ZShyYWNlID0gY2FzZV93aGVuKAogICAgUTMuM183X1RFWFQgPT0gIk5hdGl2ZSBBbWVyaWNhbi8gQWZyaWNhbiBhbWVyY2luZyIgfiAiQmlyYWNpYWwgb3IgTXVsdGlyYWNpYWwiLAogICAgVFJVRSB+IHJhY2UKICApKQpgYGAKCgojIEludGVyLXJhdGVyIFJlbGlhYmlsaXR5CgpUd28gcmF0ZXJzICh0aGUgZmlyc3QgdHdvIGF1dGhvcnMpIGNvbXBsZXRlZCB2b3dlbCBzZWdtZW50YXRpb24gZm9yIHRoZSBzcGVha2Vycy4gVG8gY2FsY3VsYXRlIGludGVyLXJhdGVyIHJlbGlhYmlsaXR5LCAyMCUgb2YgdGhlIHNwZWFrZXJzIHdlcmUgc2VnbWVudGVkIGFnYWluIGJ5IHRoZSBvdGhlciByYXRlci4gVHdvLXdheSBpbnRyYWNsYXNzIGNvZWZmaWNpZW50cyB3ZXJlIGNvbXB1dGVkIGZvciB0aGUgZXh0cmFjdGVkIEYxIGFuZCBGMiBmcm9tIHRoZSB0ZW1wb3JhbCBtaWRwb2ludCBvZiB0aGUgdm93ZWwgc2VnbWVudHMuIFNpbmNlIG9ubHkgb25lIHNldCBvZiByYXRpbmdzIHdpbGwgYmUgdXNlZCBpbiB0aGUgZGF0YSBhbmFseXNpcywgd2UgZm9jdXMgb24gdGhlIHNpbmdsZSBJQ0MgcmVzdWx0cyBhbmQgaW50ZXJwcmV0YXRpb24uIEhvd2V2ZXIsIHdlIGFsc28gcmVwb3J0IHRoZSBhdmVyYWdlIElDQyB2YWx1ZXMgdG8gYmUgY29tcHJlaGVuc2l2ZS4KCmBgYHtyfQoKIyMgQ3JlYXRpbmcgbmV3IGRhdGEgZnJhbWVzIHRvIGNhbGN1bGF0ZSBJQ0MgZm9yIGV4dHJhY3RlZCBGMSBhbmQgRjIgdmFsdWVzCgpGMV9SZWwgPC0gUmVsaWFiaWxpdHkgJT4lCiAgZHBseXI6OnNlbGVjdChjKEYxLCBGMV9yZWwpKQoKRjJfUmVsIDwtIFJlbGlhYmlsaXR5ICU+JQogIGRwbHlyOjpzZWxlY3QoYyhGMiwgRjJfcmVsKSkKICAKIyMgU2luZ2xlIElDQyBmb3IgRjEKU2luZ2xlX0YxIDwtIGlycjo6aWNjKEYxX1JlbCwgbW9kZWwgPSAidHdvd2F5IiwgdHlwZSA9ICJhZ3JlZW1lbnQiLCB1bml0ID0gInNpbmdsZSIpCgojIyBBdmVyYWdlIElDQyBmb3IgRjEKQXZlcmFnZV9GMSA8LSBpcnI6OmljYyhGMV9SZWwsIG1vZGVsID0gInR3b3dheSIsIHR5cGUgPSAiYWdyZWVtZW50IiwgdW5pdCA9ICJhdmVyYWdlIikKCiMjIFNpbmdsZSBJQ0MgZm9yIEYyClNpbmdsZV9GMiA8LSBpcnI6OmljYyhGMl9SZWwsIG1vZGVsID0gInR3b3dheSIsIHR5cGUgPSAiYWdyZWVtZW50IiwgdW5pdCA9ICJzaW5nbGUiKQoKIyMgQXZlcmFnZSBJQ0MgZm9yIEYyCkF2ZXJhZ2VfRjIgPC0gaXJyOjppY2MoRjJfUmVsLCBtb2RlbCA9ICJ0d293YXkiLCB0eXBlID0gImFncmVlbWVudCIsIHVuaXQgPSAiYXZlcmFnZSIpCgojIyBJbnRlci1yYXRlciByZWxpYWJpbGl0eSByZXN1bHRzIGFuZCBpbnRlcnByZXRhdGlvbgogIHByaW50KHBhc3RlKCJTaW5nbGUgSUNDIGZvciBGMSBpcyAiLAogICAgICAgICAgICAgIHJvdW5kKFNpbmdsZV9GMSR2YWx1ZSwgZGlnaXRzID0gMyksCiAgICAgICAgICAgICAgIi4gIiwgCiAgICAgICAgICAgICAgIlRoZSA5NSUgQ0kgaXMgWyIsCiAgICAgICAgICAgICAgcm91bmQoU2luZ2xlX0YxJGxib3VuZCwgZGlnaXRzID0gMyksCiAgICAgICAgICAgICAgIiAtICIsCiAgICAgICAgICAgICAgcm91bmQoU2luZ2xlX0YxJHVib3VuZCwgZGlnaXRzID0gMyksCiAgICAgICAgICAgICAgIl0uIiwKICAgICAgICAgICAgICBzZXAgPSAiIikpCiAgCiAgcHJpbnQocGFzdGUoIlNpbmdsZSBJQ0MgZm9yIEYyIGlzICIsCiAgICAgICAgICAgICAgcm91bmQoU2luZ2xlX0YyJHZhbHVlLCBkaWdpdHMgPSAzKSwKICAgICAgICAgICAgICAiLiAiLCAKICAgICAgICAgICAgICAiVGhlIDk1JSBDSSBpcyBbIiwKICAgICAgICAgICAgICByb3VuZChTaW5nbGVfRjIkbGJvdW5kLCBkaWdpdHMgPSAzKSwKICAgICAgICAgICAgICAiIC0gIiwgcm91bmQoU2luZ2xlX0YyJHVib3VuZCwgZGlnaXRzID0gMyksCiAgICAgICAgICAgICAgIl0uIiwKICAgICAgICAgICAgICBzZXAgPSAiIikpCiAgCiAgcHJpbnQocGFzdGUoIkF2ZXJhZ2UgSUNDIGZvciBGMSBpcyAiLAogICAgICAgICAgICAgIHJvdW5kKEF2ZXJhZ2VfRjEkdmFsdWUsIGRpZ2l0cyA9IDMpLAogICAgICAgICAgICAgICIuICIsIAogICAgICAgICAgICAgICJUaGUgOTUlIENJIGlzIFsiLAogICAgICAgICAgICAgIHJvdW5kKEF2ZXJhZ2VfRjEkbGJvdW5kLCBkaWdpdHMgPSAzKSwKICAgICAgICAgICAgICAiIC0gIiwKICAgICAgICAgICAgICByb3VuZChBdmVyYWdlX0YxJHVib3VuZCwgZGlnaXRzID0gMyksCiAgICAgICAgICAgICAgIl0uIiwKICAgICAgICAgICAgICBzZXAgPSAiIikpCiAgCiAgcHJpbnQocGFzdGUoIkF2ZXJhZ2UgSUNDIGZvciBGMiBpcyAiLAogICAgICAgICAgICAgIHJvdW5kKEF2ZXJhZ2VfRjIkdmFsdWUsIGRpZ2l0cyA9IDMpLAogICAgICAgICAgICAgICIuICIsIAogICAgICAgICAgICAgICJUaGUgOTUlIENJIGlzIFsiLAogICAgICAgICAgICAgIHJvdW5kKEF2ZXJhZ2VfRjIkbGJvdW5kLCBkaWdpdHMgPSAzKSwKICAgICAgICAgICAgICAiIC0gIiwKICAgICAgICAgICAgICByb3VuZChBdmVyYWdlX0YyJHVib3VuZCwgZGlnaXRzID0gMyksCiAgICAgICAgICAgICAgIl0uIiwKICAgICAgICAgICAgICBzZXAgPSAiIikpCiAgCiAgcHJpbnQoIlRodXMsIGludGVycmF0ZXIgcmVsaWFiaWxpdHkgZm9yIHRoZSBleHRyYWN0ZWQgRjEgYW5kIEYyIHZhbHVlcyBmcm9tIHRoZSB2b3dlbCBzZWdtZW50cyB3YXMgZ29vZCB0byBleGNlbGxlbnQuIikKCiMjIFJlbW92aW5nIGV4dHJhIGRhdGEgZnJhbWVzIGZyb20gZW52aXJvbm1lbnQKcm0oRjFfUmVsLCBGMl9SZWwsIFJlbGlhYmlsaXR5LCBTaW5nbGVfRjEsIFNpbmdsZV9GMiwgQXZlcmFnZV9GMSwgQXZlcmFnZV9GMikKCmBgYAoKCiMgRGVzY3JpcHRpdmUgU3RhdGlzdGljcwoKIyMgQ29ycmVsYXRpb25zCgpgYGB7cn0KIyBDcmVhdGVzIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXgKQ29yck1hdHJpeCA8LSBBY291c3RpY0RhdGEgJT4lCiAgZHBseXI6OnNlbGVjdChWU0FfYiwgdm93ZWxfRURfYiwgSHVsbF9iLCBIdWxsX2JWU0RfMjUsIEh1bGxfYlZTRF83NSwgVkFTLCB0cmFuc0FjYykgJT4lCiAgYXMubWF0cml4KCkgJT4lCiAgSG1pc2M6OnJjb3JyKCkKQ29yck1hdHJpeAoKIyBJZGVudGlmaWVzIHNpZ25pZmljYW50IGNvcnJlbGF0aW9ucwpDb3JyTWF0cml4UCA8LSBDb3JyTWF0cml4JFAgPCAuMDUKCiMgUHVsbHMgb3V0IHR3byBleGFtcGxlIGNvcnJlbGF0aW9ucyB0byBiZSBzcGVjaWZpZWQgaW4gdGhlIG1hbnVzY3JpcHQKc3RhdHM6OmNvci50ZXN0KEFjb3VzdGljRGF0YSRWU0FfYiwgQWNvdXN0aWNEYXRhJHZvd2VsX0VEX2IsIG1ldGhvZCA9ICJwZWFyc29uIikKc3RhdHM6OmNvci50ZXN0KEFjb3VzdGljRGF0YSRIdWxsX2IsIEFjb3VzdGljRGF0YSRIdWxsX2JWU0RfMjUsIG1ldGhvZCA9ICJwZWFyc29uIikKCiMgU2F2ZXMgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeCB0byB0aGUgIlRhYmxlcyIgZm9sZGVyCndyaXRlLmNzdihDb3JyTWF0cml4LCBmaWxlID0gIlRhYmxlcy9Db3JyZWxhdGlvbiBNYXRyaXguY3N2IikKCiMgUmVtb3ZlcyB1bndhdGVkIHZhcmlhYmxlcwpybShDb3JyTWF0cml4KQoKYGBgCgojIFJlc2VhcmNoIFExOiBNb2RlbGluZyBJbnRlbGxpZ2liaWxpdHkKCiMjIE9ydGhvZ3JhcGhpYyBUcmFuc2NyaXB0aW9ucwojIyMgTW9kZWwgMQpgYGB7cn0KCiMgU3BlY2lmeWluZyBNb2RlbCAxCk9UX01vZGVsMSA8LSBsbSh0cmFuc0FjYyB+IEh1bGxfYlZTRF8yNSwgZGF0YSA9IEFjb3VzdGljRGF0YSkKCiMjIE1vZGVsIDEgQXNzdW1wdGlvbnMgCnBlcmZvcm1hbmNlOjpjaGVja19tb2RlbChPVF9Nb2RlbDEpCgojIyBNb2RlbCAxIFN1bW1hcnkKc3VtbWFyeShPVF9Nb2RlbDEpCgpgYGAKCiMjIyBNb2RlbCAyCmBgYHtyfQoKIyMgU3BlY2lmeWluZyBNb2RlbCAyCk9UX01vZGVsMiA8LSBsbSh0cmFuc0FjYyB+IEh1bGxfYlZTRF8yNSArIEh1bGxfYlZTRF83NSwgZGF0YSA9IEFjb3VzdGljRGF0YSkKCiMjIE1vZGVsIDIgQXNzdW1wdGlvbiBDaGVjawpwZXJmb3JtYW5jZTo6Y2hlY2tfbW9kZWwoT1RfTW9kZWwyKQoKIyMgTW9kZWwgMiBTdW1tYXJ5CnN1bW1hcnkoT1RfTW9kZWwyKQoKIyMgTW9kZWwgMSBhbmQgTW9kZWwgMiBDb21wYXJpc29uCmFub3ZhKE9UX01vZGVsMSwgT1RfTW9kZWwyKQoKYGBgCgojIyMgTW9kZWwgM2EKCmBgYHtyfQoKIyMgU3BlY2lmeWluZyBNb2RlbCAzCk9UX01vZGVsM2EgPC0gbG0odHJhbnNBY2MgfiBIdWxsX2JWU0RfMjUgKyBIdWxsX2JWU0RfNzUgKyBIdWxsX2IsIGRhdGEgPSBBY291c3RpY0RhdGEpCgojIyBNb2RlbCAzIEFzc3VtcHRpb24gQ2hlY2sKcGVyZm9ybWFuY2U6OmNoZWNrX21vZGVsKE9UX01vZGVsM2EpCnBlcmZvcm1hbmNlOjpjaGVja19jb2xsaW5lYXJpdHkoT1RfTW9kZWwzYSkKCiMjIE1vZGVsIDMgU3VtbWFyeQpzdW1tYXJ5KE9UX01vZGVsM2EpCgojIyBNb2RlbCAyIGFuZCBNb2RlbCAzIENvbXBhcmlzb24KYW5vdmEoT1RfTW9kZWwyLCBPVF9Nb2RlbDNhKQoKYGBgCgojIyMgTW9kZWwgM2IKYGBge3J9CgojIyBTcGVjaWZ5aW5nIE1vZGVsIDMKCk9UX01vZGVsM2IgPC0gbG0odHJhbnNBY2MgfiBIdWxsX2JWU0RfNzUgKyBIdWxsX2IsIGRhdGEgPSBBY291c3RpY0RhdGEpCgojIyBNb2RlbCAzIEFzc3VtcHRpb24gQ2hlY2sKCnBlcmZvcm1hbmNlOjpjaGVja19tb2RlbChPVF9Nb2RlbDNiKQpwZXJmb3JtYW5jZTo6Y2hlY2tfY29sbGluZWFyaXR5KE9UX01vZGVsM2IpCgoKIyMgTW9kZWwgMyBTdW1tYXJ5CgpzdW1tYXJ5KE9UX01vZGVsM2IpCgpgYGAKCiMjIyBNb2RlbCA0CmBgYHtyfQoKIyMgU3BlY2lmeWluZyBNb2RlbCA0CgpPVF9Nb2RlbDQgPC0gbG0odHJhbnNBY2MgfiBIdWxsX2JWU0RfNzUgKyBIdWxsX2IgKyBWU0FfYiwgZGF0YSA9IEFjb3VzdGljRGF0YSkKCiMjIE1vZGVsIDQgQXNzdW1wdGlvbiBDaGVjawoKcGVyZm9ybWFuY2U6OmNoZWNrX21vZGVsKE9UX01vZGVsNCkKcGVyZm9ybWFuY2U6OmNoZWNrX2NvbGxpbmVhcml0eShPVF9Nb2RlbDQpCgojIyBNb2RlbCA0IFN1bW1hcnkKCnN1bW1hcnkoT1RfTW9kZWw0KQoKIyMgTW9kZWwgMyBhbmQgTW9kZWwgNCBDb21wYXJpc29uCgphbm92YShPVF9Nb2RlbDNiLCBPVF9Nb2RlbDQpCgpgYGAKCiMjIyBNb2RlbCA1CmBgYHtyfQoKIyMgU3BlY2lmeWluZyBNb2RlbCA1CgpPVF9Nb2RlbDUgPC0gbG0odHJhbnNBY2MgfiBIdWxsX2JWU0RfNzUgKyBWU0FfYiArIHZvd2VsX0VEX2IsIGRhdGEgPSBBY291c3RpY0RhdGEpCgojIyBNb2RlbCA0IEFzc3VtcHRpb24gQ2hlY2sKCnBlcmZvcm1hbmNlOjpjaGVja19tb2RlbChPVF9Nb2RlbDUpCnBlcmZvcm1hbmNlOjpjaGVja19jb2xsaW5lYXJpdHkoT1RfTW9kZWw1KQoKIyMgTW9kZWwgNCBTdW1tYXJ5CgpzdW1tYXJ5KE9UX01vZGVsNSkKCiMjIE1vZGVsIDMgYW5kIE1vZGVsIDQgQ29tcGFyaXNvbgoKYW5vdmEoT1RfTW9kZWw0LCBPVF9Nb2RlbDUpCgpgYGAKCgojIyMgRmluYWwgTW9kZWwKCmBgYHtyfQoKIyMgU3BlY2lmeWluZyBGaW5hbCBNb2RlbAoKT1RfTW9kZWxfZmluYWwgPC0gbG0odHJhbnNBY2MgfiBWU0FfYiwgZGF0YSA9IEFjb3VzdGljRGF0YSkKCiMjIEZpbmFsIE1vZGVsIEFzc3VtcHRpb24gQ2hlY2sKCnBlcmZvcm1hbmNlOjpjaGVja19tb2RlbChPVF9Nb2RlbF9maW5hbCkKCiMjIEZpbmFsIE1vZGVsIFN1bW1hcnkKCnN1bW1hcnkoT1RfTW9kZWxfZmluYWwpCmNvbmZpbnQoT1RfTW9kZWxfZmluYWwpCgpgYGAKCiMjIFZBUyBNb2RlbHMKCiMjIyBNb2RlbCAxCmBgYHtyfQoKIyBTcGVjaWZ5aW5nIE1vZGVsIDEKClZBU19Nb2RlbDEgPC0gbG0oVkFTIH4gSHVsbF9iVlNEXzI1LCBkYXRhID0gQWNvdXN0aWNEYXRhKQoKIyMgTW9kZWwgMSBBc3N1bXB0aW9ucyAKCnBlcmZvcm1hbmNlOjpjaGVja19tb2RlbChWQVNfTW9kZWwxKQoKIyMgTW9kZWwgMSBTdW1tYXJ5CgpzdW1tYXJ5KFZBU19Nb2RlbDEpCgpgYGAKCiMjIyBNb2RlbCAyCmBgYHtyfQoKIyMgU3BlY2lmeWluZyBNb2RlbCAyCgpWQVNfTW9kZWwyIDwtIGxtKFZBUyB+IEh1bGxfYlZTRF8yNSArIEh1bGxfYlZTRF83NSwgZGF0YSA9IEFjb3VzdGljRGF0YSkKCiMjIE1vZGVsIDIgQXNzdW1wdGlvbiBDaGVjawoKcGVyZm9ybWFuY2U6OmNoZWNrX21vZGVsKFZBU19Nb2RlbDIpCgojIyBNb2RlbCAyIFN1bW1hcnkKCnN1bW1hcnkoVkFTX01vZGVsMikKCiMjIE1vZGVsIDEgYW5kIE1vZGVsIDIgQ29tcGFyaXNvbgoKYW5vdmEoVkFTX01vZGVsMSwgVkFTX01vZGVsMikKCmBgYAoKIyMjIE1vZGVsIDNhCmBgYHtyfQoKIyMgU3BlY2lmeWluZyBNb2RlbCAzCgpWQVNfTW9kZWwzYSA8LSBsbShWQVMgfiBIdWxsX2JWU0RfMjUgKyBIdWxsX2JWU0RfNzUgKyBIdWxsX2IsIGRhdGEgPSBBY291c3RpY0RhdGEpCgojIyBNb2RlbCAzIEFzc3VtcHRpb24gQ2hlY2sKCnBlcmZvcm1hbmNlOjpjaGVja19tb2RlbChWQVNfTW9kZWwzYSkKcGVyZm9ybWFuY2U6OmNoZWNrX2NvbGxpbmVhcml0eShWQVNfTW9kZWwzYSkKCiMjIE1vZGVsIDMgU3VtbWFyeQoKc3VtbWFyeShWQVNfTW9kZWwzYSkKCiMjIE1vZGVsIDIgYW5kIE1vZGVsIDMgQ29tcGFyaXNvbgoKYW5vdmEoVkFTX01vZGVsMiwgVkFTX01vZGVsM2EpCgpgYGAKCiMjIyBNb2RlbCAzYgpUaGlzIG1vZGVsIHJlbW92ZXMgVlNEMjUgYmVjYXVzZSBvZiBpdCdzIGhpZ2ggVklGIHZhbHVlID4gNS4KYGBge3J9CgojIyBTcGVjaWZ5aW5nIE1vZGVsIDNiCgpWQVNfTW9kZWwzYiA8LSBsbShWQVMgfiBIdWxsX2JWU0RfNzUgKyBIdWxsX2IsIGRhdGEgPSBBY291c3RpY0RhdGEpCgojIyBNb2RlbCAzIEFzc3VtcHRpb24gQ2hlY2sKCnBlcmZvcm1hbmNlOjpjaGVja19tb2RlbChWQVNfTW9kZWwzYikKcGVyZm9ybWFuY2U6OmNoZWNrX2NvbGxpbmVhcml0eShWQVNfTW9kZWwzYikKCiMjIE1vZGVsIDMgU3VtbWFyeQoKc3VtbWFyeShWQVNfTW9kZWwzYikKCmBgYAojIyMgTW9kZWwgNApgYGB7cn0KCiMjIFNwZWNpZnlpbmcgTW9kZWwgNAoKVkFTX01vZGVsNCA8LSBsbShWQVMgfiBIdWxsX2JWU0RfNzUgKyBIdWxsX2IgKyBWU0FfYiwgZGF0YSA9IEFjb3VzdGljRGF0YSkKCiMjIE1vZGVsIDQgQXNzdW1wdGlvbiBDaGVjawoKcGVyZm9ybWFuY2U6OmNoZWNrX21vZGVsKFZBU19Nb2RlbDQpCnBlcmZvcm1hbmNlOjpjaGVja19jb2xsaW5lYXJpdHkoVkFTX01vZGVsNCkKCiMjIE1vZGVsIDQgU3VtbWFyeQoKc3VtbWFyeShWQVNfTW9kZWw0KQoKIyMgTW9kZWwgMyBhbmQgTW9kZWwgNCBDb21wYXJpc29uCgphbm92YShWQVNfTW9kZWwzYiwgVkFTX01vZGVsNCkKCmBgYAoKIyMjIE1vZGVsIDUKYGBge3J9CgojIyBTcGVjaWZ5aW5nIE1vZGVsIDUKClZBU19Nb2RlbDUgPC0gbG0oVkFTIH4gSHVsbF9iVlNEXzc1ICsgSHVsbF9iICsgVlNBX2IgKyB2b3dlbF9FRF9iLCBkYXRhID0gQWNvdXN0aWNEYXRhKQoKIyMgTW9kZWwgNSBBc3N1bXB0aW9uIENoZWNrCgpwZXJmb3JtYW5jZTo6Y2hlY2tfbW9kZWwoVkFTX01vZGVsNSkKCiMjIE1vZGVsIDUgU3VtbWFyeQoKc3VtbWFyeShWQVNfTW9kZWw1KQoKIyMgTW9kZWwgNCBhbmQgTW9kZWwgNSBDb21wYXJpc29uCgphbm92YShWQVNfTW9kZWw0LCBWQVNfTW9kZWw1KQoKYGBgCgojIyMgRmluYWwgTW9kZWwKCmBgYHtyfQoKIyMgU3BlY2lmeWluZyBGaW5hbCBNb2RlbAoKVkFTX01vZGVsX2ZpbmFsIDwtIGxtKFZBUyB+IFZTQV9iLCBkYXRhID0gQWNvdXN0aWNEYXRhKQoKIyMgRmluYWwgTW9kZWwgQXNzdW1wdGlvbiBDaGVjawoKcGVyZm9ybWFuY2U6OmNoZWNrX21vZGVsKFZBU19Nb2RlbF9maW5hbCkKCiMjIEZpbmFsIE1vZGVsIFN1bW1hcnkKCnN1bW1hcnkoVkFTX01vZGVsX2ZpbmFsKQpjb25maW50KFZBU19Nb2RlbF9maW5hbCkKCmBgYAoKIyBSZXNlYXJjaCBRMjogUmVsYXRpb25zaGlwIGJldHdlZW4gT1QgYW5kIFZBUwoKTW9kZWwgMQpgYGB7cn0KCiMgU3BlY2lmeSBNb2RlbAoKT1RfVkFTX21vZGVsIDwtIGxtKHRyYW5zQWNjIH4gVkFTKkV0aW9sb2d5ICsgVkFTKlNleCwgZGF0YSA9IEFjb3VzdGljRGF0YSkKCiMgQXNzdW1wdGlvbiBDaGVjawoKcGVyZm9ybWFuY2U6OmNoZWNrX21vZGVsKE9UX1ZBU19tb2RlbCkKCiMgTW9kZWwgUmVzdWx0cwoKc3VtbWFyeShPVF9WQVNfbW9kZWwpCgpgYGAKCiMjIEZpbmFsIExpbmVhciBNb2RlbAoKYGBge3J9CgojIFNwZWNpZnkgRmluYWwgTW9kZWwKCk9UX1ZBU19maW5hbCA8LSBsbSh0cmFuc0FjYyB+IFZBUywgZGF0YSA9IEFjb3VzdGljRGF0YSkKCmNvbmZpbnQoT1RfVkFTX2ZpbmFsKQoKIyBNb2RlbCBSZXN1bHRzCgpzdW1tYXJ5KE9UX1ZBU19maW5hbCkKCmBgYAoKIyBDb3JuZXIgRGlzcGVyc2lvbgpMb29raW5nIGF0IGNvcm5lciBkaXNwZXJzaW9uIGFzIHRoZSBzb2xlIHByZWRpY3Rvci4KCmBgYHtyfQoKIyBTcGVjaWZ5IEZpbmFsIE1vZGVsCgpPVF9jb3JuRGlzcCA8LSBsbSh0cmFuc0FjYyB+IHZvd2VsX0VEX2IsIGRhdGEgPSBBY291c3RpY0RhdGEpCnN1bW1hcnkoT1RfY29ybkRpc3ApCgpWQVNfY29ybkRpc3AgPC0gbG0oVkFTIH4gdm93ZWxfRURfYiwgZGF0YSA9IEFjb3VzdGljRGF0YSkKc3VtbWFyeShWQVNfY29ybkRpc3ApCgpgYGAKIyBNYW51c2NyaXB0IFRhYmxlcwojIyBEZXNjcmlwdGl2ZXMgVGFibGUKYGBge3J9Cmd0RGF0YSA8LSBBY291c3RpY0RhdGEgJT4lCiAgcmJpbmQoLixBY291c3RpY0RhdGEgJT4lCiAgICAgICAgICBkcGx5cjo6bXV0YXRlKEV0aW9sb2d5ID0gIkFsbCBFdGlvbG9naWVzIikpICU+JQogIHJiaW5kKC4sQWNvdXN0aWNEYXRhICU+JQogICAgICAgICAgcmJpbmQoLixBY291c3RpY0RhdGEgJT4lCiAgICAgICAgICBkcGx5cjo6bXV0YXRlKEV0aW9sb2d5ID0gIkFsbCBFdGlvbG9naWVzIikpICU+JQogICAgICAgICAgZHBseXI6Om11dGF0ZShTZXggPSAiQWxsIikpICU+JQogIGRwbHlyOjptdXRhdGUoU2V4ID0gYXMuZmFjdG9yKFNleCksCiAgICAgICAgICAgICAgICBFdGlvbG9neSA9IGFzLmZhY3RvcihFdGlvbG9neSkpICU+JQogIGRwbHlyOjpncm91cF9ieShTZXgsIEV0aW9sb2d5KSAlPiUKICBkcGx5cjo6c3VtbWFyaXplKFZTQV9tZWFuID0gbWVhbihWU0FfYiwgbmEucm0gPVQpLAogICAgICAgICAgICAgICAgICAgVlNBX3NkID0gc2QoVlNBX2IsIG5hLnJtID0gVCksCiAgICAgICAgICAgICAgICAgICBEaXNwX21lYW4gPSBtZWFuKHZvd2VsX0VEX2IsIG5hLnJtID1UKSwKICAgICAgICAgICAgICAgICAgIERpc3Bfc2QgPSBzZCh2b3dlbF9FRF9iLCBuYS5ybSA9VCksCiAgICAgICAgICAgICAgICAgICBIdWxsX21lYW4gPSBtZWFuKEh1bGxfYiwgbmEucm0gPVQpLAogICAgICAgICAgICAgICAgICAgSHVsbF9zZCA9IHNkKEh1bGxfYiwgbmEucm0gPVQpLAogICAgICAgICAgICAgICAgICAgVlNEMjVfbWVhbiA9IG1lYW4oSHVsbF9iVlNEXzI1LCBuYS5ybSA9VCksCiAgICAgICAgICAgICAgICAgICBWU0QyNV9zZCA9IHNkKEh1bGxfYlZTRF8yNSwgbmEucm0gPVQpLAogICAgICAgICAgICAgICAgICAgVlNENzVfbWVhbiA9IG1lYW4oSHVsbF9iVlNEXzc1LCBuYS5ybSA9VCksCiAgICAgICAgICAgICAgICAgICBWU0Q3NV9zZCA9IHNkKEh1bGxfYlZTRF83NSwgbmEucm0gPVQpLAogICAgICAgICAgICAgICAgICAgVkFTX21lYW4gPSBtZWFuKFZBUywgbmEucm0gPVQpLAogICAgICAgICAgICAgICAgICAgVkFTX3NkID0gc2QoVkFTLCBuYS5ybSA9VCksCiAgICAgICAgICAgICAgICAgICBPVF9tZWFuID0gbWVhbih0cmFuc0FjYywgbmEucm0gPVQpLAogICAgICAgICAgICAgICAgICAgT1Rfc2QgPSBzZCh0cmFuc0FjYywgbmEucm0gPVQpKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IFZTQV9tZWFuOk9UX3NkLCBuYW1lc190byA9ICJNZWFzdXJlIiwKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIlZhbHVlIikgJT4lCiAgZHBseXI6Om11dGF0ZShWYWx1ZSA9IHJvdW5kKFZhbHVlLCBkaWdpdHMgPSAyKSwKICAgICAgICAgICAgICAgIG1lYW5TRCA9IGlmZWxzZShncmVwbCgiX21lYW4iLE1lYXN1cmUpLCJNIiwic2QiKSwKICAgICAgICAgICAgICAgIE1lYXN1cmUgPSBnc3ViKCJfbWVhbiIsIiIsTWVhc3VyZSksCiAgICAgICAgICAgICAgICBNZWFzdXJlID0gZ3N1YigiX3NkIiwiIixNZWFzdXJlKSwKICAgICAgICAgICAgICAgIEV0aW9sb2d5ID0gcGFzdGUoRXRpb2xvZ3ksbWVhblNELCBzZXAgPSAiXyIpLAogICAgICAgICAgICAgICAgU2V4ID0gY2FzZV93aGVuKAogICAgICAgICAgICAgICAgICBTZXggPT0gIkFsbCIgfiAiQWxsIFNwZWFrZXJzIiwKICAgICAgICAgICAgICAgICAgU2V4ID09ICJNIiB+ICJNYWxlIFNwZWFrZXJzIiwKICAgICAgICAgICAgICAgICAgU2V4ID09ICJGIiB+ICJGZW1hbGUgU3BlYWtlcnMiCiAgICAgICAgICAgICAgICApKSAlPiUKICBkcGx5cjo6c2VsZWN0KCFtZWFuU0QpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBFdGlvbG9neSwgdmFsdWVzX2Zyb20gPSAiVmFsdWUiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKE1lYXN1cmUgIT0gIlZTRDUwIikKCmd0RGF0YSAlPiUKICBndDo6Z3QoCiAgICByb3duYW1lX2NvbCA9ICJNZWFzdXJlIiwKICAgIGdyb3VwbmFtZV9jb2wgPSAiU2V4IiwKICApICU+JQogIGZtdF9udW1iZXIoCiAgICBjb2x1bW5zID0gJ0FsbCBFdGlvbG9naWVzX00nOlBEX3NkLAogICAgZGVjaW1hbHMgPSAyCiAgKSAlPiUKICB0YWJfc3Bhbm5lcigKICAgIGxhYmVsID0gIkFsbCBFdGlvbG9naWVzIiwKICAgIGNvbHVtbnMgPSBjKCdBbGwgRXRpb2xvZ2llc19NJywgJ0FsbCBFdGlvbG9naWVzX3NkJykKICApICU+JQogICAgdGFiX3NwYW5uZXIoCiAgICBsYWJlbCA9ICJBTFMiLAogICAgY29sdW1ucyA9IGMoQUxTX00sIEFMU19zZCkKICApICU+JQogIHRhYl9zcGFubmVyKAogICAgbGFiZWwgPSAiUEQiLAogICAgY29sdW1ucyA9IGMoUERfTSwgUERfc2QpCiAgKSAlPiUKICB0YWJfc3Bhbm5lcigKICAgIGxhYmVsID0gIkhEIiwKICAgIGNvbHVtbnMgPSBjKEhEX00sIEhEX3NkKQogICkgJT4lCiAgdGFiX3NwYW5uZXIoCiAgICBsYWJlbCA9ICJBdGF4aWMiLAogICAgY29sdW1ucyA9IGMoQXRheGljX00sIEF0YXhpY19zZCkKICApICU+JQogIGd0Ojpjb2xzX21vdmVfdG9fc3RhcnQoCiAgICBjb2x1bW5zID0gYygnQWxsIEV0aW9sb2dpZXNfTScsJ0FsbCBFdGlvbG9naWVzX3NkJykKICApICU+JQogIHJvd19ncm91cF9vcmRlcigKICAgIGdyb3VwcyA9IGMoIkFsbCBTcGVha2VycyIsICJGZW1hbGUgU3BlYWtlcnMiLCAiTWFsZSBTcGVha2VycyIpCiAgICApICU+JQogIGNvbHNfbGFiZWwoCiAgICAgJ0FsbCBFdGlvbG9naWVzX00nID0gIk0iLAogICAgICdBbGwgRXRpb2xvZ2llc19zZCcgPSAiU0QiLAogICAgIEFMU19NID0gIk0iLAogICAgIEFMU19zZCA9ICJTRCIsCiAgICAgUERfTSA9ICJNIiwKICAgICBQRF9zZCA9ICJTRCIsCiAgICAgSERfTSA9ICJNIiwKICAgICBIRF9zZCA9ICJTRCIsCiAgICAgQXRheGljX00gPSAiTSIsCiAgICAgQXRheGljX3NkID0gIlNEIgogICkgJT4lCiAgZ3RzYXZlKCJEZXNjcmlwdGl2ZXNUYWJsZS5odG1sIiwgcGF0aCA9ICJUYWJsZXMiKQoKYGBgCgojIyBPVCBNb2RlbApgYGB7cn0Kc2pQbG90Ojp0YWJfbW9kZWwoT1RfTW9kZWwxLAogICAgICAgICAgICAgICAgICBPVF9Nb2RlbDIsCiAgICAgICAgICAgICAgICAgIE9UX01vZGVsM2IsCiAgICAgICAgICAgICAgICAgIE9UX01vZGVsNCwKICAgICAgICAgICAgICAgICAgT1RfTW9kZWw1LAogICAgICAgICAgICAgICAgICBPVF9Nb2RlbF9maW5hbCwKICAgICAgICAgICAgICAgICAgc2hvdy5jaSA9IEYsCiAgICAgICAgICAgICAgICAgIHAuc3R5bGUgPSAic3RhcnMiLAogICAgICAgICAgICAgICAgICBmaWxlID0gIlRhYmxlcy9PVCBNb2RlbHMuaHRtbCIpCmBgYAoKIyMgVkFTIE1vZGVsCmBgYHtyfQpzalBsb3Q6OnRhYl9tb2RlbChWQVNfTW9kZWwxLAogICAgICAgICAgICAgICAgICBWQVNfTW9kZWwyLAogICAgICAgICAgICAgICAgICBWQVNfTW9kZWwzLAogICAgICAgICAgICAgICAgICBWQVNfTW9kZWw0LAogICAgICAgICAgICAgICAgICBWQVNfTW9kZWw1LAogICAgICAgICAgICAgICAgICBWQVNfTW9kZWxfZmluYWwsCiAgICAgICAgICAgICAgICAgIHNob3cuY2kgPSBGLAogICAgICAgICAgICAgICAgICBwLnN0eWxlID0gInN0YXJzIiwKICAgICAgICAgICAgICAgICAgZmlsZSA9ICJUYWJsZXMvVkFTIE1vZGVscy5odG1sIikKYGBgCgojIyBPVCB2cy4gVkFTCmBgYHtyfQpzalBsb3Q6OnRhYl9tb2RlbChPVF9WQVNfbW9kZWwsT1RfVkFTX2ZpbmFsLAogICAgICAgICAgICAgICAgICBzaG93LmNpID0gRiwKICAgICAgICAgICAgICAgICAgc2hvdy5yZWZsdmwgPSBUUlVFLAogICAgICAgICAgICAgICAgICBwLnN0eWxlID0gInN0YXJzIiwKICAgICAgICAgICAgICAgICAgZmlsZSA9ICJUYWJsZXMvT1QgYW5kIFZBUyBDb21wYXJpc29uLmh0bWwiKQpgYGAKCiMgTWFudXNjcmlwdCBGaWd1cmVzCiMjIEV4YW1wbGUgTWVhc3VyZXMKYGBge3J9CmZvcm1hbnRDb2xvciA8LSAiZ3JleSIKZm9ybWFudEFscGhhIDwtIC45NQpsaW5lQ29sb3IgPC0gIndoaXRlIgpsaW5lQWxwaGEgPC0gLjgKCnZvd2VsRGF0YSA8LSByaW86OmltcG9ydCgiUHJlcHBlZCBEYXRhL1Zvd2VsIERhdGEuY3N2IikgJT4lCiAgZHBseXI6OmZpbHRlcihTcGVha2VyID09ICJBRjgiKQoKICBQaXRjaF9QUkFBVCA8LSBsaXN0LmZpbGVzKHBhdGggPSBwYXN0ZSgiUHJlcHBlZCBEYXRhL0V4YW1wbGUgRGF0YS8iLCBzZXAgPSAiIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIi5QaXRjaCIsIGlnbm9yZS5jYXNlID0gVCkgJT4lCiAgICBwYXN0ZSgiUHJlcHBlZCBEYXRhL0V4YW1wbGUgRGF0YS8iLC4sIHNlcCA9ICIiKSAlPiUKICAgIHJlYWQuZGVsaW0oLiwgaGVhZGVyID0gRikgJT4lCiAgICBkcGx5cjo6cmVuYW1lKFBpdGNoID0gVjEpICU+JQogICAgZHBseXI6Om11dGF0ZShQaXRjaCA9IGdzdWIoIi0tdW5kZWZpbmVkLS0iLE5BLFBpdGNoKSwKICAgICAgICAgICAgICAgICAgUGl0Y2ggPSBhcy5udW1lcmljKFBpdGNoKSkKICAKICBGb3JtYW50c19QUkFBVCA8LSBsaXN0LmZpbGVzKHBhdGggPSBwYXN0ZSgiUHJlcHBlZCBEYXRhL0V4YW1wbGUgRGF0YS8iLCBzZXAgPSAiIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIl9Gb3JtYW50IiwgaWdub3JlLmNhc2UgPSBUKSAlPiUKICAgIHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsLiwgc2VwID0gIiIpICU+JQogICAgcmVhZC5kZWxpbSguLCBoZWFkZXIgPSBUKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoIWMobmZvcm1hbnRzLCBCMS5Iei4sIEIyLkh6LiwgQjMuSHouLCBGNC5Iei4sIEI0Lkh6LiwgRjUuSHouLCBCNS5Iei4pKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoVGltZV9zID0gdGltZS5zLiwKICAgICAgICAgICAgICAgICAgRjFfSHogPSBGMS5Iei4sCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gRjIuSHouLAogICAgICAgICAgICAgICAgICBGM19IeiA9IEYzLkh6LikgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX0h6ID0gaWZlbHNlKEYxX0h6ID09IDAsIE5BLCBGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gaWZlbHNlKEYyX0h6ID09IDAsIE5BLCBGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gaWZlbHNlKEYzX0h6ID09IDAsIE5BLCBGM19IeikpICU+JQogICAgZHBseXI6Om11dGF0ZShGMV9IeiA9IGFzLm51bWVyaWMoRjFfSHopLAogICAgICAgICAgICAgICAgICBGMl9IeiA9IGFzLm51bWVyaWMoRjJfSHopLAogICAgICAgICAgICAgICAgICBGM19IeiA9IHN1cHByZXNzV2FybmluZ3MoYXMubnVtZXJpYyhGM19IeikpLAogICAgICAgICAgICAgICAgICBUaW1lX21zID0gVGltZV9zIC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjFfa0h6ID0gRjFfSHogLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMl9rSHogPSBGMl9IeiAvIDEwMDAsCiAgICAgICAgICAgICAgICAgIEYzX2tIeiA9IEYzX0h6IC8gMTAwMCkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KCFUaW1lX3MpICU+JQogICAgZHBseXI6OnJlbG9jYXRlKFRpbWVfbXMsIC5iZWZvcmUgPSBGMV9IeikgJT4lCiAgICBjYmluZCguLFBpdGNoX1BSQUFUKQogIAogIGMgPC0gMgogIHdoaWxlKGMgPCBOUk9XKEZvcm1hbnRzX1BSQUFUKSl7CiAgICBGb3JtYW50c19QUkFBVCRGMV9IeltjXSA8LSBpZmVsc2UoaXMubmEoRm9ybWFudHNfUFJBQVQkRjFfSHpbYy0xXSkgJiYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYxX0h6W2MrMV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZvcm1hbnRzX1BSQUFUJEYxX0h6W2NdKQogICAgRm9ybWFudHNfUFJBQVQkRjJfSHpbY10gPC0gaWZlbHNlKGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYyX0h6W2MtMV0pICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpcy5uYShGb3JtYW50c19QUkFBVCRGMl9IeltjKzFdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGb3JtYW50c19QUkFBVCRGMl9IeltjXSkKICAgIGMgPC0gYyArIDEKICB9CiAgcm0oYykKICAKICBGb3JtYW50c19QUkFBVCA8LSBGb3JtYW50c19QUkFBVCAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKFBpdGNoKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX21hZCA9IChhYnMoRjFfSHogLSBtZWRpYW4oRjFfSHopKS8gbWFkKEYxX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41LAogICAgICAgICAgICAgICAgICBGMl9tYWQgPSAoYWJzKEYyX0h6IC0gbWVkaWFuKEYyX0h6KSkvIG1hZChGMl9IeiwgY29uc3RhbnQgPSAxLjQ4MjYpKSA+IDIuNSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKEYxX21hZCA9PSBGQUxTRSAmIEYyX21hZCA9PSBGQUxTRSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKG1EaXN0ID0gbWFoYWxhbm9iaXMoY2JpbmQoLiRGMV9IeiwgLiRGMl9IeiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sTWVhbnMoY2JpbmQoLiRGMV9IeiwgLiRGMl9IeikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdiA9IGNvdihjYmluZCguJEYxX0h6LCAuJEYyX0h6KSkpLAogICAgICAgICAgICAgICAgICBtRGlzdF9zZCA9IGFicyhzY2FsZShtRGlzdCxjZW50ZXIgPSBUKSkpICU+JQogICAgZHBseXI6OmZpbHRlcihtRGlzdF9zZCA8IDIpICU+JQogICAgZHBseXI6OnNlbGVjdCghYyhGMV9tYWQsIEYyX21hZCwgbURpc3QsIG1EaXN0X3NkKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX3ogPSBzY2FsZShGMV9IeiwgY2VudGVyID0gVFJVRSksCiAgICAgICAgICAgICAgICAgIEYyX3ogPSBzY2FsZShGMl9IeiwgY2VudGVyID0gVFJVRSksCiAgICAgICAgICAgICAgICAgIEYzX3ogPSBzY2FsZShGM19IeiwgY2VudGVyID0gVFJVRSksCiAgICAgICAgICAgICAgICAgIEYxX2IgPSBlbXVSOjpiYXJrKEYxX0h6KSwKICAgICAgICAgICAgICAgICAgRjJfYiA9IGVtdVI6OmJhcmsoRjJfSHopLAogICAgICAgICAgICAgICAgICBGM19iID0gZW11Ujo6YmFyayhGM19IeikpCiAgCiAgcm0oUGl0Y2hfUFJBQVQpCiAgCiAgCiMjIENvcm5lciBEaXNwZXJzaW9uIC0tLS0KICB3ZWRnZSA8LSB2b3dlbERhdGEgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoVm93ZWwpICU+JQogICAgZHBseXI6OnN1bW1hcml6ZShtZWFuX0YxID0gbWVhbihGMV90ZW1wTWlkKSwKICAgICAgICAgICAgICBtZWFuX0YyID0gbWVhbihGMl90ZW1wTWlkKSwKICAgICAgICAgICAgICBtZWFuX0YxX3ogPSBtZWFuKEYxX3pfdGVtcE1pZCksCiAgICAgICAgICAgICAgbWVhbl9GMl96ID0gbWVhbihGMl96X3RlbXBNaWQpLAogICAgICAgICAgICAgIG1lYW5fRjFfYiA9IG1lYW4oRjFfYl90ZW1wTWlkKSwKICAgICAgICAgICAgICBtZWFuX0YyX2IgPSBtZWFuKEYyX2JfdGVtcE1pZCkpICU+JQogICAgZHBseXI6OmZpbHRlcihWb3dlbCA9PSAidiIpCiAgICAKICBjb3JuZXJfZGlzIDwtIHZvd2VsRGF0YSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoVm93ZWwgIT0gInYiKSAlPiUKICAgIGRwbHlyOjpncm91cF9ieShWb3dlbCkgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXplKG1lYW5fRjEgPSBtZWFuKEYxX3RlbXBNaWQpLAogICAgICAgICAgICAgIG1lYW5fRjIgPSBtZWFuKEYyX3RlbXBNaWQpLAogICAgICAgICAgICAgIG1lYW5fRjFfeiA9IG1lYW4oRjFfel90ZW1wTWlkKSwKICAgICAgICAgICAgICBtZWFuX0YyX3ogPSBtZWFuKEYyX3pfdGVtcE1pZCksCiAgICAgICAgICAgICAgbWVhbl9GMV9iID0gbWVhbihGMV9iX3RlbXBNaWQpLAogICAgICAgICAgICAgIG1lYW5fRjJfYiA9IG1lYW4oRjJfYl90ZW1wTWlkKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKFZvd2VsX0VEID0gc3FydCgobWVhbl9GMS13ZWRnZSRtZWFuX0YxKV4yICsgKG1lYW5fRjItd2VkZ2UkbWVhbl9GMileMiksCiAgICAgICAgICAgICAgICAgIFZvd2VsX0VEX3ogPSBzcXJ0KChtZWFuX0YxX3otd2VkZ2UkbWVhbl9GMV96KV4yICsgKG1lYW5fRjJfei13ZWRnZSRtZWFuX0YyX3opXjIpLAogICAgICAgICAgICAgICAgICBWb3dlbF9FRF9iID0gc3FydCgobWVhbl9GMV9iLXdlZGdlJG1lYW5fRjFfYileMiArIChtZWFuX0YyX2Itd2VkZ2UkbWVhbl9GMl9iKV4yKSkKCiAgICAKIyBQbG90IENvcm5lciBEaXNwZXJzaW9uCiAgICAgICMgQ2hhbmdpbmcgdG8gSVBBIHN5bWJvbHMKICAgICAgY29ybmVyX2RpcyA8LSBjb3JuZXJfZGlzICU+JQogICAgICAgIGRwbHlyOjptdXRhdGUoVm93ZWwgPSBkcGx5cjo6Y2FzZV93aGVuKAogICAgICAgICAgVm93ZWwgPT0gImFlIiB+ICLDpiIsCiAgICAgICAgICBUUlVFIH4gVm93ZWwKICAgICAgICApKQogICAgICAKICAgICAgd2VkZ2UgPC0gd2VkZ2UgJT4lCiAgICAgICAgZHBseXI6Om11dGF0ZShWb3dlbCA9IGNhc2Vfd2hlbigKICAgICAgICAgIFZvd2VsID09ICJ2IiB+ICLKjCIsCiAgICAgICAgICBUUlVFIH4gVm93ZWwKICAgICAgICApKQogICAgICAKICAgICAgQ0RwbG90IDwtIGdncGxvdChhZXMoeD1GMl9iLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5PUYxX2IpLAogICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBGb3JtYW50c19QUkFBVCwKICAgICAgICAgICAgICAgICAgICAgICBpbmhlcml0LmFlcyA9IEZBTFNFKSArIAogICAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsCiAgICAgICAgICAgICAgICAgYWxwaGEgPSBmb3JtYW50QWxwaGEsCiAgICAgICAgICAgICAgICAgY29sb3IgPSBmb3JtYW50Q29sb3IpICsgCiAgICAgIGdlb21fbGluZShhZXMoeCA9IG1lYW5fRjJfYiwKICAgICAgICAgICAgICAgICAgICB5ID0gbWVhbl9GMV9iKSwKICAgICAgICAgICAgICAgIGRhdGEgPSBjb3JuZXJfZGlzICU+JQogICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KFZvd2VsOm1lYW5fRjJfYikgJT4lCiAgICAgICAgICAgICAgICAgIGRwbHlyOjpmaWx0ZXIoVm93ZWwgPT0gImkiKSAlPiUKICAgICAgICAgICAgICAgICAgcmJpbmQoLix3ZWRnZSksCiAgICAgICAgICAgICAgICBjb2xvciA9IGxpbmVDb2xvciwKICAgICAgICAgICAgICAgIHNpemUgPSAxLjUsCiAgICAgICAgICAgICAgICBhbHBoYSA9IGxpbmVBbHBoYSkgKwogICAgICBnZW9tX2xpbmUoYWVzKHggPSBtZWFuX0YyX2IsCiAgICAgICAgICAgICAgICAgICAgeSA9IG1lYW5fRjFfYiksCiAgICAgICAgICAgICAgICBkYXRhID0gY29ybmVyX2RpcyAlPiUKICAgICAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChWb3dlbDptZWFuX0YyX2IpICU+JQogICAgICAgICAgICAgICAgICBkcGx5cjo6ZmlsdGVyKFZvd2VsID09ICJhIikgJT4lCiAgICAgICAgICAgICAgICAgIHJiaW5kKC4sd2VkZ2UpLAogICAgICAgICAgICAgICAgY29sb3IgPSBsaW5lQ29sb3IsCiAgICAgICAgICAgICAgICBzaXplID0gMS41LAogICAgICAgICAgICAgICAgYWxwaGEgPSBsaW5lQWxwaGEpICsKICAgICAgZ2VvbV9saW5lKGFlcyh4ID0gbWVhbl9GMl9iLAogICAgICAgICAgICAgICAgICAgIHkgPSBtZWFuX0YxX2IpLAogICAgICAgICAgICAgICAgZGF0YSA9IGNvcm5lcl9kaXMgJT4lCiAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoVm93ZWw6bWVhbl9GMl9iKSAlPiUKICAgICAgICAgICAgICAgICAgZHBseXI6OmZpbHRlcihWb3dlbCA9PSAiw6YiKSAlPiUKICAgICAgICAgICAgICAgICAgcmJpbmQoLix3ZWRnZSksCiAgICAgICAgICAgICAgICBjb2xvciA9IGxpbmVDb2xvciwKICAgICAgICAgICAgICAgIHNpemUgPSAxLjUsCiAgICAgICAgICAgICAgICBhbHBoYSA9IGxpbmVBbHBoYSkgKwogICAgICBnZW9tX2xpbmUoYWVzKHggPSBtZWFuX0YyX2IsCiAgICAgICAgICAgICAgICAgICAgeSA9IG1lYW5fRjFfYiksCiAgICAgICAgICAgICAgICBkYXRhID0gY29ybmVyX2RpcyAlPiUKICAgICAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChWb3dlbDptZWFuX0YyX2IpICU+JQogICAgICAgICAgICAgICAgICBkcGx5cjo6ZmlsdGVyKFZvd2VsID09ICJ1IikgJT4lCiAgICAgICAgICAgICAgICAgIHJiaW5kKC4sd2VkZ2UpLAogICAgICAgICAgICAgICAgY29sb3IgPSBsaW5lQ29sb3IsCiAgICAgICAgICAgICAgICBzaXplID0gMS41LAogICAgICAgICAgICAgICAgYWxwaGEgPSBsaW5lQWxwaGEpICsKICAgICAgZ2VvbV9wb2ludChhZXMoeCA9IG1lYW5fRjJfYiwKICAgICAgICAgICAgICAgICAgICAgeSA9IG1lYW5fRjFfYiwKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBWb3dlbCksCiAgICAgICAgICAgICAgICAgZGF0YSA9IGNvcm5lcl9kaXMgJT4lCiAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoVm93ZWw6bWVhbl9GMl9iKSAlPiUKICAgICAgICAgICAgICAgICAgcmJpbmQoLix3ZWRnZSksCiAgICAgICAgICAgICAgICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICBzaXplID0gNSkgKwogICAgICBzY2FsZV95X3JldmVyc2UoKSArCiAgICAgIHNjYWxlX3hfcmV2ZXJzZSgpICsKICAgICAgdGhlbWVfY2xhc3NpYygpICsgbGFicyh0aXRsZSA9IHBhc3RlKCJDb3JuZXIgRGlzcGVyc2lvbiIpKSArIHhsYWIoIkYyIChCYXJrKSIpICsgeWxhYigiRjEgKEJhcmspIikgKwogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkgKwogICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImEiID0gIiMxQUFENzciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIsOmIiA9ICIjMTI3OUI1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJpIiA9ICIjRkZCRjAwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ1IiA9ICIjRkQ3ODUzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICLKjCIgPSAiI0JGMzE3OCIpKQogICAgQ0RwbG90CiAgICAKICAgICAgcm0oY29ybmVyX2Rpcywgd2VkZ2UpCiAgICAgIAojIyBWb3dlbCBTcGFjZSBBcmVhIC0tLS0KICBWU0FfY29vcmRzIDwtIHZvd2VsRGF0YSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoVm93ZWwgIT0gInYiKSAlPiUKICAgIGRwbHlyOjpncm91cF9ieShWb3dlbCkgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXplKG1lYW5fRjEgPSBtZWFuKEYxX3RlbXBNaWQpLAogICAgICAgICAgICAgIG1lYW5fRjIgPSBtZWFuKEYyX3RlbXBNaWQpLAogICAgICAgICAgICAgIG1lYW5fRjFfeiA9IG1lYW4oRjFfel90ZW1wTWlkKSwKICAgICAgICAgICAgICBtZWFuX0YyX3ogPSBtZWFuKEYyX3pfdGVtcE1pZCksCiAgICAgICAgICAgICAgbWVhbl9GMV9iID0gbWVhbihGMV9iX3RlbXBNaWQpLAogICAgICAgICAgICAgIG1lYW5fRjJfYiA9IG1lYW4oRjJfYl90ZW1wTWlkKSkgCiAgCiMjIyBQbG90dGluZyBWU0EKICAgIFZTQV9jb29yZHMgPC0gVlNBX2Nvb3JkcyAlPiUKICAgICAgICBkcGx5cjo6bXV0YXRlKFZvd2VsID0gY2FzZV93aGVuKAogICAgICAgICAgVm93ZWwgPT0gImFlIiB+ICLDpiIsCiAgICAgICAgICBUUlVFIH4gVm93ZWwKICAgICAgICApKQogICAgCiAgICBWU0FwbG90IDwtIGdncGxvdChhZXMoeCA9IEYyX2IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IEYxX2IpLAogICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IEZvcm1hbnRzX1BSQUFULAogICAgICAgICAgICAgICAgICAgICAgaW5oZXJpdC5hZXMgPSBGQUxTRSkgKyAKICAgICAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLAogICAgICAgICAgICAgICAgIGFscGhhID0gZm9ybWFudEFscGhhLAogICAgICAgICAgICAgICAgIGNvbG9yID0gZm9ybWFudENvbG9yKSArIAogICAgICBnZW9tX3BvbHlnb24oYWVzKHggPSBtZWFuX0YyX2IsCiAgICAgICAgICAgICAgICAgICAgICAgeSA9IG1lYW5fRjFfYiksCiAgICAgICAgICAgICAgICAgICBkYXRhID0gVlNBX2Nvb3JkcywKICAgICAgICAgICAgICAgICAgIGFscGhhID0gbGluZUFscGhhLAogICAgICAgICAgICAgICAgICAgY29sb3IgPSBsaW5lQ29sb3IsCiAgICAgICAgICAgICAgICAgICBmaWxsPU5BLAogICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEuNSkgKwogICAgICBnZW9tX3BvaW50KGFlcyh4ID0gbWVhbl9GMl9iLAogICAgICAgICAgICAgICAgICAgICB5ID0gbWVhbl9GMV9iLAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IFZvd2VsKSwKICAgICAgICAgICAgICAgICBkYXRhID0gVlNBX2Nvb3JkcywKICAgICAgICAgICAgICAgICBpbmhlcml0LmFlcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgIHNpemUgPSA1KSArCiAgICAgIHNjYWxlX3lfcmV2ZXJzZSgpICsKICAgICAgc2NhbGVfeF9yZXZlcnNlKCkgKwogICAgICBndWlkZXMoY29sb3IgPSBGQUxTRSkgKwogICAgICB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHRpdGxlID0gIlZTQSIpICsgeGxhYigiRjIgKEJhcmspIikgKyB5bGFiKCJGMSAoQmFyaykiKSArCiAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgICAgICBhc3BlY3QucmF0aW8gPSAxKSArCiAgICAgICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYSIgPSAiIzFBQUQ3NyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiw6YiID0gIiMxMjc5QjUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImkiID0gIiNGRkJGMDAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInUiID0gIiNGRDc4NTMiKSkKICAgIFZTQXBsb3QKICAKICBybShWU0FfY29vcmRzKQogIAojIyBIdWxsIC0tLS0KIyMjIFBsb3R0aW5nIEh1bGwKICAgICAgY29udmV4Q29vcmRzIDwtIEZvcm1hbnRzX1BSQUFUICU+JQogICAgICAgIGRwbHlyOjpzZWxlY3QoRjFfYiwgRjJfYikgJT4lCiAgICAgICAgYXMubWF0cml4KCkgJT4lCiAgICAgICAgZ3JEZXZpY2VzOjpjaHVsbCgpCiAgICAgIGNvbnZleCA8LSBGb3JtYW50c19QUkFBVCAlPiUKICAgICAgICBzbGljZShjb252ZXhDb29yZHMpCgogICAgICBodWxsUGxvdCA8LSBnZ3Bsb3QoYWVzKEYyX2IsIEYxX2IpLAogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IEZvcm1hbnRzX1BSQUFUKSArCiAgICAgICAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLAogICAgICAgICAgICAgICAgIGFscGhhID0gZm9ybWFudEFscGhhLAogICAgICAgICAgICAgICAgIGNvbG9yID0gZm9ybWFudENvbG9yKSArCiAgICAgICAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBjb252ZXgsCiAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gLjUsCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIiMxMjc5QjUiLAogICAgICAgICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxLjUpICsKICAgICAgICBzY2FsZV95X3JldmVyc2UoKSArCiAgICAgICAgc2NhbGVfeF9yZXZlcnNlKCkgKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKSArIGxhYnModGl0bGUgPSBleHByZXNzaW9uKCJWU0EiW0h1bGxdKSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJGMiAoQmFyaykiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkYxIChCYXJrKSIpICsKICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICAgIGFzcGVjdC5yYXRpbyA9IDEpCiAgICAgIGh1bGxQbG90CiAgICAKICAKIyMgVm93ZWwgU3BhY2UgRGVuc2l0eSAtLS0tCgojIEJhcmsgTm9ybWFsaXplZCBEZW5zaXR5IC0tLS0KIyBzZWxlY3RpbmcgdGhlIGJhbmR3aWR0aApIX2hwaSA8LSBrczo6SHBpKHggPSBGb3JtYW50c19QUkFBVFssYygiRjJfYiIsIkYxX2IiKV0sIHBpbG90ID0gInNhbXNlIiwgcHJlID0gInNjYWxlIiwgYmlubmVkID0gVCkKCiMgY29tcHV0ZSAyZCBrZGUKayA8LSBrZGUoeCA9IEZvcm1hbnRzX1BSQUFUWyxjKCJGMl9iIiwiRjFfYiIpXSwKICAgICAgICAgSCA9IEhfaHBpLAogICAgICAgICBiaW5uZWQgPSBULAogICAgICAgICBncmlkc2l6ZSA9IDI1MCkKCiNkZW5zaXR5IDwtIGtbWyJlc3RpbWF0ZSJdXQoKIyBCZWZvcmUgd2UgY2FuIHBsb3QgdGhlIGRlbnNpdHkgZXN0aW1hdGUgd2UgbmVlZCB0byBtZWx0IGl0IGludG8gbG9uZyBmb3JtYXQKbWF0Lm1lbHRlZCA8LSBkYXRhLnRhYmxlOjptZWx0KGskZXN0aW1hdGUpCm5hbWVzKG1hdC5tZWx0ZWQpIDwtIGMoIngiLCAieSIsICJkZW5zaXR5IikKCiMgV2UgbmVlZCB0byBhZGQgdHdvIG1vcmUgY29sdW1zIHRvIHByZXNlcnZlIHRoZSBheGVzIHVuaXRzCm1hdC5tZWx0ZWQkRjIuYiA8LSByZXAoayRldmFsLnBvaW50c1tbMV1dLCB0aW1lcyA9IG5yb3coayRlc3RpbWF0ZSkpCm1hdC5tZWx0ZWQkRjEuYiA8LSByZXAoayRldmFsLnBvaW50c1tbMl1dLCBlYWNoID0gbnJvdyhrJGVzdGltYXRlKSkKbWF0Lm1lbHRlZCRkZW5zaXR5IDwtIHNjYWxlczo6cmVzY2FsZShtYXQubWVsdGVkJGRlbnNpdHksIHRvID0gYygwLCAxKSkKCiMgVlNEIC0gMjUKblZTRF8yNSA8LSBtYXQubWVsdGVkICU+JQogIGRwbHlyOjpmaWx0ZXIoZGVuc2l0eSA+IC4yNSkgJT4lCiAgZHBseXI6OnNlbGVjdChGMi5iLEYxLmIsIGRlbnNpdHkpICU+JQogIGRwbHlyOjpyZW5hbWUoRGVuc2l0eSA9IGRlbnNpdHkpCgpjb252ZXhDb29yZHMgPC0gblZTRF8yNSAlPiUKICBkcGx5cjo6c2VsZWN0KEYyLmIsIEYxLmIpICU+JQogIGFzLm1hdHJpeCgpICU+JQogICNnckRldmljZXM6Onh5LmNvb3JkcygpICU+JQogIGdyRGV2aWNlczo6Y2h1bGwoKQpuY29udmV4XzI1IDwtIG5WU0RfMjUgJT4lCiAgc2xpY2UoY29udmV4Q29vcmRzKQoKIyBWU0QgLSA3NQpuVlNEXzc1IDwtIG1hdC5tZWx0ZWQgJT4lCiAgZHBseXI6OmZpbHRlcihkZW5zaXR5ID4gLjc1KSAlPiUKICBkcGx5cjo6c2VsZWN0KEYyLmIsRjEuYiwgZGVuc2l0eSkgJT4lCiAgZHBseXI6OnJlbmFtZShEZW5zaXR5ID0gZGVuc2l0eSkKCmNvbnZleENvb3JkcyA8LSBuVlNEXzc1ICU+JQogIGRwbHlyOjpzZWxlY3QoRjIuYiwgRjEuYikgJT4lCiAgYXMubWF0cml4KCkgJT4lCiAgZ3JEZXZpY2VzOjpjaHVsbCgpCm5jb252ZXhfNzUgPC0gblZTRF83NSAlPiUKICBzbGljZShjb252ZXhDb29yZHMpCgojIFBsb3R0aW5nIFogTm9ybWFsaXplZCBWU0QgCiAgICByZiA8LSBjb2xvclJhbXBQYWxldHRlKHJldihSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoMTEsICJTcGVjdHJhbCIpKSkKICAgIHIgPC0gcmYoMzIpCiAgICAKICAgIHBsb3REYXRhIDwtIG1hdC5tZWx0ZWQgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpyZW5hbWUoRGVuc2l0eSA9IGRlbnNpdHkpICU+JQogICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6bXV0YXRlKFZTRGxhYmVsID0gZHBseXI6OmNhc2Vfd2hlbigKICAgICAgICAgICAgICAgICAgICAgICAgICBEZW5zaXR5IDwgLjI1IH4gIm5vbmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgIERlbnNpdHkgPiAuMjUgJiYgRGVuc2l0eSA8IC43NSB+ICJWU0QyNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJWU0Q3NSIKICAgICAgICAgICAgICAgICAgICAgICAgKSkKZ2VvbS50ZXh0LnNpemUgPC0gMgogICAgVlNEcGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IHBsb3REYXRhLAogICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBGMi5iLAogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBGMS5iLAogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBEZW5zaXR5KSkgKyAKICAgICAgZ2VvbV90aWxlKCkgKyAKICAgICAgc2NhbGVfZmlsbF92aXJpZGlzX2MoKSArCiAgICAgIHNjYWxlX3hfcmV2ZXJzZShleHBhbmQgPSBjKDAsIDApLCAKICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHJvdW5kKHNlcShtaW4obWF0Lm1lbHRlZCRGMi5iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4KG1hdC5tZWx0ZWQkRjIuYiksIGJ5ID0gMikpKSArCiAgICAgIHNjYWxlX3lfcmV2ZXJzZShleHBhbmQgPSBjKDAsIDApLAogICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gcm91bmQoc2VxKG1pbihtYXQubWVsdGVkJEYxLmIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heChtYXQubWVsdGVkJEYxLmIpLCBieSA9IDIpKSkgKyAKICAgICAgeWxhYigiRjEgKEJhcmspIikgKyB4bGFiKCJGMiAoQmFyaykiKSArCiAgICAgIGxhYnModGl0bGUgPSAiVlNEIikgKwogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkgKwogICAgICBnZW9tX3BvbHlnb24oZGF0YSA9IG5jb252ZXhfMjUsIGFscGhhID0gbGluZUFscGhhLCBjb2xvciA9IGxpbmVDb2xvciwgc2l6ZSA9IDEuNSwgZmlsbCA9IE5BLCBsaW5ldHlwZSA9IDIpICsKICAgICAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBuY29udmV4Xzc1LCBhbHBoYSA9IGxpbmVBbHBoYSwgY29sb3IgPSBsaW5lQ29sb3IsIHNpemUgPSAxLjUsIGZpbGwgPSBOQSwgbGluZXR5cGUgPSAxKSArCiAgICAjIFZTRCAyNSBMYWJlbAogICAgICBhbm5vdGF0ZShnZW9tID0gImN1cnZlIiwKICAgICAgICAgICAgICAgeCA9IDYuOSwgeSA9IDEuNysuNSwKICAgICAgICAgICAgICAgeGVuZCA9IDguNSwgeWVuZCA9IDMuNSwKICAgICAgICAgICAgICAgY3VydmF0dXJlID0gLS4zLAogICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMiwgIm1tIikpLAogICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIpICsKICAgICAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwKICAgICAgICAgICAgICAgeCA9IDcuNSwgeSA9IDEuNywKICAgICAgICAgICAgICAgbGFiZWwgPSBkZXBhcnNlKGJxdW90ZShWU0RbMjVdKSksCiAgICAgICAgICAgICAgIGhqdXN0ID0gImNlbnRlciIsCiAgICAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwKICAgICAgICAgICAgICAgcGFyc2U9VFJVRSkgKwogICAgIyBWU0QgNzUgTGFiZWwKICAgICAgYW5ub3RhdGUoZ2VvbSA9ICJjdXJ2ZSIsCiAgICAgICAgICAgICAgIHggPSA3LjUsIHkgPSA3LjUtLjUsCiAgICAgICAgICAgICAgIHhlbmQgPSAxMS4zNSwgeWVuZCA9IDUuNSwKICAgICAgICAgICAgICAgY3VydmF0dXJlID0gLjMsCiAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgyLCAibW0iKSksCiAgICAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIikgKwogICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLAogICAgICAgICAgICAgICB4ID0gNywgeSA9IDcuNSwKICAgICAgICAgICAgICAgbGFiZWwgPSBkZXBhcnNlKGJxdW90ZShWU0RbNzVdKSksCiAgICAgICAgICAgICAgIGhqdXN0ID0gImNlbnRlciIsCiAgICAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwKICAgICAgICAgICAgICAgcGFyc2UgPSBUUlVFKQogICAgIFZTRHBsb3QKCiMgQ29tYmluZWQgUGxvdAogICAgIAogICAgIHJvdzEgPC0gVlNBcGxvdCArIENEcGxvdCArCiAgICAgICAgcGF0Y2h3b3JrOjpwbG90X2xheW91dChndWlkZXMgPSAnY29sbGVjdCcsCiAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMikgJiB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAncmlnaHQnKQogICAgIHJvdzIgPC0gaHVsbFBsb3QgKyBWU0RwbG90ICsKICAgICAgICBwYXRjaHdvcms6OnBsb3RfbGF5b3V0KGd1aWRlcyA9ICdjb2xsZWN0JywKICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAyKSAmIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdyaWdodCcpCiAgICAgCiAgICAgbWVhc3VyZXNQbG90IDwtIHJvdzEgLyByb3cyICsgcGF0Y2h3b3JrOjpwbG90X2xheW91dChoZWlnaHRzID0gYygxLzIsIDEvMiksIGJ5cm93ID0gRkFMU0UpCiAgICAgbWVhc3VyZXNQbG90CiAgICAgCiAgICAgcm0ocm93MSwgcm93MikKCmdnc2F2ZShmaWxlbmFtZSA9ICJQbG90cy9NZWFzdXJlcy5wbmciLAogICAgICAgcGxvdCA9IG1lYXN1cmVzUGxvdCwKICAgICAgIGhlaWdodCA9IDUuNSwKICAgICAgIHdpZHRoID0gNiwKICAgICAgIHNjYWxlID0gLjgpCgpgYGAKCiMjIEZpbHRlcmluZyBQcm9jZXNzCmBgYHtyfQpmb3JtYW50QWxwaGEgPC0gLjIwCm15UGFsIDwtIGMoIiMxMjc5QjUiLCIjMkQyRDM3IikKClBpdGNoX1BSQUFUIDwtIGxpc3QuZmlsZXMocGF0aCA9IHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsIHNlcCA9ICIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIi5QaXRjaCIsIGlnbm9yZS5jYXNlID0gVCkgJT4lCiAgICBwYXN0ZSgiUHJlcHBlZCBEYXRhL0V4YW1wbGUgRGF0YS8iLC4sIHNlcCA9ICIiKSAlPiUKICAgIHJlYWQuZGVsaW0oLiwgaGVhZGVyID0gRikgJT4lCiAgICBkcGx5cjo6cmVuYW1lKFBpdGNoID0gVjEpICU+JQogICAgZHBseXI6Om11dGF0ZShQaXRjaCA9IGdzdWIoIi0tdW5kZWZpbmVkLS0iLE5BLFBpdGNoKSwKICAgICAgICAgICAgICAgICAgUGl0Y2ggPSBhcy5udW1lcmljKFBpdGNoKSkKCkZvcm1hbnRzX1BSQUFUIDwtIGxpc3QuZmlsZXMocGF0aCA9IHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsIHNlcCA9ICIiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiX0Zvcm1hbnQiLCBpZ25vcmUuY2FzZSA9IFQpICU+JQogICAgcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEvIiwuLCBzZXAgPSAiIikgJT4lCiAgICByZWFkLmRlbGltKC4sIGhlYWRlciA9IFQpICU+JQogICAgZHBseXI6OnNlbGVjdCghYyhuZm9ybWFudHMsIEIxLkh6LiwgQjIuSHouLCBCMy5Iei4sIEY0Lkh6LiwgQjQuSHouLCBGNS5Iei4sIEI1Lkh6LikpICU+JQogICAgZHBseXI6OnJlbmFtZShUaW1lX3MgPSB0aW1lLnMuLAogICAgICAgICAgICAgICAgICBGMV9IeiA9IEYxLkh6LiwKICAgICAgICAgICAgICAgICAgRjJfSHogPSBGMi5Iei4sCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gRjMuSHouKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoRjFfSHogPSBpZmVsc2UoRjFfSHogPT0gMCwgTkEsIEYxX0h6KSwKICAgICAgICAgICAgICAgICAgRjJfSHogPSBpZmVsc2UoRjJfSHogPT0gMCwgTkEsIEYyX0h6KSwKICAgICAgICAgICAgICAgICAgRjNfSHogPSBpZmVsc2UoRjNfSHogPT0gMCwgTkEsIEYzX0h6KSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX0h6ID0gYXMubnVtZXJpYyhGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gYXMubnVtZXJpYyhGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gc3VwcHJlc3NXYXJuaW5ncyhhcy5udW1lcmljKEYzX0h6KSksCiAgICAgICAgICAgICAgICAgIFRpbWVfbXMgPSBUaW1lX3MgLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMV9rSHogPSBGMV9IeiAvIDEwMDAsCiAgICAgICAgICAgICAgICAgIEYyX2tIeiA9IEYyX0h6IC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjNfa0h6ID0gRjNfSHogLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMV9iID0gZW11Ujo6YmFyayhGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX2IgPSBlbXVSOjpiYXJrKEYyX0h6KSwKICAgICAgICAgICAgICAgICAgRjNfYiA9IGVtdVI6OmJhcmsoRjNfSHopKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoIVRpbWVfcykgJT4lCiAgICBkcGx5cjo6cmVsb2NhdGUoVGltZV9tcywgLmJlZm9yZSA9IEYxX0h6KSAlPiUKICAgIGNiaW5kKC4sUGl0Y2hfUFJBQVQpCiAgCiAgYyA8LSAyCiAgd2hpbGUoYyA8IE5ST1coRm9ybWFudHNfUFJBQVQpKXsKICAgIEZvcm1hbnRzX1BSQUFUJEYxX0h6W2NdIDwtIGlmZWxzZShpcy5uYShGb3JtYW50c19QUkFBVCRGMV9IeltjLTFdKSAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoRm9ybWFudHNfUFJBQVQkRjFfSHpbYysxXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRm9ybWFudHNfUFJBQVQkRjFfSHpbY10pCiAgICBGb3JtYW50c19QUkFBVCRGMl9IeltjXSA8LSBpZmVsc2UoaXMubmEoRm9ybWFudHNfUFJBQVQkRjJfSHpbYy0xXSkgJiYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYyX0h6W2MrMV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZvcm1hbnRzX1BSQUFUJEYyX0h6W2NdKQogICAgYyA8LSBjICsgMQogIH0KICBybShjKQogIAogICMgUmF3IEZvcm1hbnRzIC0tLS0KICBmMSA8LSBnZ3Bsb3QoYWVzKHg9RjJfYiwKICAgICAgICAgICAgICAgICAgIHk9RjFfYiksCiAgICAgICAgICAgICAgIGRhdGEgPSBGb3JtYW50c19QUkFBVCkgKyAKICAgICAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBjb2xvciA9IG15UGFsWzJdKSArCiAgICAgIHNjYWxlX3lfcmV2ZXJzZShsaW1pdHMgPSBjKDE2LDApKSArCiAgICAgIHNjYWxlX3hfcmV2ZXJzZShsaW1pdHMgPSBjKDE5LDMpKSArCiAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBteVBhbCkgKwogICAgICB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIlJhdyBGb3JtYW50XG5WYWx1ZXMiKSkgKyB4bGFiKCJGMiAoQmFyaykiKSArIHlsYWIoIkYxIChCYXJrKSIpICsKICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICAgIGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpCiAgICAKIyBTdGVwICMxOiBWb2ljZWQgU2VnbWVudHMgLS0tLQogICAgcGxvdERhdGEgPC0gRm9ybWFudHNfUFJBQVQgJT4lCiAgICAgICAgICAgICAgICAgICBkcGx5cjo6bXV0YXRlKGlzT3V0bGllciA9IGNhc2Vfd2hlbigKICAgICAgICAgICAgICAgICAgICAgaXMubmEoUGl0Y2gpIH4gIlJlbW92ZWQiLAogICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIlJldGFpbmVkIgogICAgICAgICAgICAgICAgICAgKSkKICAgIGYyIDwtIGdncGxvdChkYXRhID0gcGxvdERhdGEsCiAgICAgICAgICAgICAgICAgYWVzKHggPSBGMl9iLAogICAgICAgICAgICAgICAgICAgICB5ID0gRjFfYiwKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBpc091dGxpZXIpKSArIAogICAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIGRhdGEgPSBwbG90RGF0YSAlPiUKICAgICAgICAgICAgICAgICAgIGRwbHlyOjpmaWx0ZXIoaXNPdXRsaWVyID09ICJSZW1vdmVkIikpICsKICAgICAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBkYXRhID0gcGxvdERhdGEgJT4lCiAgICAgICAgICAgICBkcGx5cjo6ZmlsdGVyKGlzT3V0bGllciA9PSAiUmV0YWluZWQiKSkgKwogICAgICBzY2FsZV95X3JldmVyc2UobGltaXRzID0gYygxNiwwKSkgKwogICAgICBzY2FsZV94X3JldmVyc2UobGltaXRzID0gYygxOSwzKSkgKwogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gbXlQYWwpICsKICAgICAgdGhlbWVfY2xhc3NpYygpICsgbGFicyh0aXRsZSA9IHBhc3RlKCJWb2ljZWQgU2VnbWVudHMiKSkgKwogICAgICB4bGFiKCJGMiAoQmFyaykiKSArCiAgICAgIHlsYWIoIkYxIChCYXJrKSIpICsKICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICAgIGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpCiAgICAKIyBTdGVwIDI6IE1BRCAtLS0tCiAgICBwbG90RGF0YSA8LSBGb3JtYW50c19QUkFBVCAlPiUKICAgICAgZHBseXI6OmZpbHRlcighaXMubmEoUGl0Y2gpKSAlPiUKICAgICAgZHBseXI6Om11dGF0ZShGMV9tYWQgPSAoYWJzKEYxX0h6IC0gbWVkaWFuKEYxX0h6KSkvIG1hZChGMV9IeiwgY29uc3RhbnQgPSAxLjQ4MjYpKSA+IDIuNSwKICAgICAgICAgICAgICAgICAgICBGMl9tYWQgPSAoYWJzKEYyX0h6IC0gbWVkaWFuKEYyX0h6KSkvIG1hZChGMl9IeiwgY29uc3RhbnQgPSAxLjQ4MjYpKSA+IDIuNSwKICAgICAgICAgICAgICAgICAgICBpc091dGxpZXIgPSBjYXNlX3doZW4oCiAgICAgICAgICAgICAgICAgICAgICBGMV9tYWQgPT0gVFJVRSB8IEYyX21hZCA9PSBUUlVFIH4gIlJlbW92ZWQiLAogICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJSZXRhaW5lZCIKICAgICAgICAgICAgICAgKSkKICAgIAogICAgZjMgPC0gZ2dwbG90KGRhdGEgPSBwbG90RGF0YSwKICAgICAgICAgICAgICAgICBhZXMoeCA9IEYyX2IsCiAgICAgICAgICAgICAgICAgICAgIHkgPSBGMV9iLAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGlzT3V0bGllcikpICsgCiAgICAgIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgZGF0YSA9IHBsb3REYXRhICU+JQogICAgICAgICAgICAgICAgICAgZHBseXI6OmZpbHRlcihpc091dGxpZXIgPT0gIlJlbW92ZWQiKSkgKwogICAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIGRhdGEgPSBwbG90RGF0YSAlPiUKICAgICAgICAgICAgIGRwbHlyOjpmaWx0ZXIoaXNPdXRsaWVyID09ICJSZXRhaW5lZCIpKSArCiAgICAgIHNjYWxlX3lfcmV2ZXJzZShsaW1pdHMgPSBjKDE2LDApKSArCiAgICAgIHNjYWxlX3hfcmV2ZXJzZShsaW1pdHMgPSBjKDE5LDMpKSArCiAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBteVBhbCkgKwogICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICBsYWJzKHRpdGxlID0gcGFzdGUoIk1lZGlhbiBBYnNvbHV0ZVxuRGV2aWF0aW9uIikpICsKICAgICAgeGxhYigiRjIgKEJhcmspIikgKwogICAgICB5bGFiKCJGMSAoQmFyaykiKSArCiAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgICAgICBhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpKQogICAgCiMgU3RlcCAzOiBNYWhhbGFuaG9iaXMgRGlzdGFuY2UgLS0tLQogIHBsb3REYXRhIDwtIEZvcm1hbnRzX1BSQUFUICU+JQogICAgICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShQaXRjaCkpICU+JQogICAgICBkcGx5cjo6bXV0YXRlKEYxX21hZCA9IChhYnMoRjFfSHogLSBtZWRpYW4oRjFfSHopKS8gbWFkKEYxX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41LAogICAgICAgICAgICAgICAgICAgIEYyX21hZCA9IChhYnMoRjJfSHogLSBtZWRpYW4oRjJfSHopKS8gbWFkKEYyX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41KSAlPiUKICAgICAgZHBseXI6OmZpbHRlcihGMV9tYWQgPT0gRkFMU0UgJiBGMl9tYWQgPT0gRkFMU0UpICU+JQogICAgICBkcGx5cjo6bXV0YXRlKG1EaXN0ID0gbWFoYWxhbm9iaXMoY2JpbmQoLiRGMV9IeiwgLiRGMl9IeiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sTWVhbnMoY2JpbmQoLiRGMV9IeiwgLiRGMl9IeikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdiA9IGNvdihjYmluZCguJEYxX0h6LCAuJEYyX0h6KSkpLAogICAgICAgICAgICAgICAgICBtRGlzdF9zZCA9IGFicyhzY2FsZShtRGlzdCxjZW50ZXIgPSBUKSksCiAgICAgICAgICAgICAgICAgIGlzT3V0bGllciA9IGNhc2Vfd2hlbigKICAgICAgICAgICAgICAgICAgICBtRGlzdF9zZCA8IDIgfiAiUmV0YWluZWQiLAogICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiUmVtb3ZlZCIKICAgICAgICAgICAgICAgICAgKSkKICAgIAogICAgZjQgPC0gZ2dwbG90KGRhdGEgPSBwbG90RGF0YSwKICAgICAgICAgICAgICAgICBhZXMoeCA9IEYyX2IsCiAgICAgICAgICAgICAgICAgICAgIHkgPSBGMV9iLAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGlzT3V0bGllcikpICsgCiAgICAgIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgZGF0YSA9IHBsb3REYXRhICU+JQogICAgICAgICAgICAgICAgICAgZHBseXI6OmZpbHRlcihpc091dGxpZXIgPT0gIlJlbW92ZWQiKSkgKwogICAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIGRhdGEgPSBwbG90RGF0YSAlPiUKICAgICAgICAgICAgIGRwbHlyOjpmaWx0ZXIoaXNPdXRsaWVyID09ICJSZXRhaW5lZCIpKSArCiAgICAgIHNjYWxlX3lfcmV2ZXJzZShsaW1pdHMgPSBjKDE2LDApKSArCiAgICAgIHNjYWxlX3hfcmV2ZXJzZShsaW1pdHMgPSBjKDE5LDMpKSArCiAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBteVBhbCkgKwogICAgICB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIk1haGFsYW5vYmlzXG5EaXN0YW5jZSIpKSArIHhsYWIoIkYyIChCYXJrKSIpICsgeWxhYigiRjEgKEJhcmspIikgKwogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgICAgYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkKICAgIAojIEZpbmFsIEZvcm1hbnRzIC0tLS0KICAgIHBsb3REYXRhIDwtIEZvcm1hbnRzX1BSQUFUICU+JQogICAgZHBseXI6OmZpbHRlcighaXMubmEoUGl0Y2gpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoRjFfbWFkID0gKGFicyhGMV9IeiAtIG1lZGlhbihGMV9IeikpLyBtYWQoRjFfSHosIGNvbnN0YW50ID0gMS40ODI2KSkgPiAyLjUsCiAgICAgICAgICAgICAgICAgIEYyX21hZCA9IChhYnMoRjJfSHogLSBtZWRpYW4oRjJfSHopKS8gbWFkKEYyX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41KSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoRjFfbWFkID09IEZBTFNFICYgRjJfbWFkID09IEZBTFNFKSAlPiUKICAgIGRwbHlyOjptdXRhdGUobURpc3QgPSBtYWhhbGFub2JpcyhjYmluZCguJEYxX0h6LCAuJEYyX0h6KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xNZWFucyhjYmluZCguJEYxX0h6LCAuJEYyX0h6KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY292ID0gY292KGNiaW5kKC4kRjFfSHosIC4kRjJfSHopKSksCiAgICAgICAgICAgICAgICAgIG1EaXN0X3NkID0gYWJzKHNjYWxlKG1EaXN0LGNlbnRlciA9IFQpKSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKG1EaXN0X3NkIDwgMikKICAgIAogICAgZjUgPC0gZ2dwbG90KGFlcyh4PUYyX2IsCiAgICAgICAgICAgICAgICAgICAgIHk9RjFfYiksCiAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHBsb3REYXRhLAogICAgICAgICAgICAgICAgICAgICAgIGluaGVyaXQuYWVzID0gRkFMU0UpICsgCiAgICAgIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgY29sb3IgPSBteVBhbFsyXSkgKyAKICAgICAgc2NhbGVfeV9yZXZlcnNlKGxpbWl0cyA9IGMoMTYsMCkpICsKICAgICAgc2NhbGVfeF9yZXZlcnNlKGxpbWl0cyA9IGMoMTksMykpICsKICAgICAgdGhlbWVfY2xhc3NpYygpICsgbGFicyh0aXRsZSA9IHBhc3RlKCJGaW5hbCBGb3JtYW50XG5UcmFqZWN0b3JpZXMiKSkgKyB4bGFiKCJGMiAoQmFyaykiKSArIHlsYWIoIkYxIChCYXJrKSIpICsKICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICAgIGFzcGVjdC5yYXRpbyA9IDEsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKICAgIAojIENvbWliaW5nIHBsb3RzCiAgICBmaWx0ZXJlZFBsb3QgPC0gZjEgKyBmMiArIGYzICsgZjQgKyBmNSArIHBhdGNod29yazo6Z3VpZGVfYXJlYSgpICsKICAgICAgcGF0Y2h3b3JrOjpwbG90X2xheW91dChndWlkZXMgPSAnY29sbGVjdCcsCiAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMykgKwogICAgICBwYXRjaHdvcms6OnBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gJ0EnKQogICAgZmlsdGVyZWRQbG90CiAgICAKICAgIGdnc2F2ZShwbG90ID0gZmlsdGVyZWRQbG90LCAiUGxvdHMvRmlsdGVyZWQgRm9ybWFudHMucG5nIiwKICAgICAgICAgICBoZWlnaHQgPSA2LAogICAgICAgICAgIHdpZHRoID0gOCwKICAgICAgICAgICB1bml0cyA9ICJpbiIsCiAgICAgICAgICAgc2NhbGUgPSAuODUpCiAgCmBgYAoKIyMgT1QgdnMuIFZBUwpgYGB7cn0KcGxvdERhdGFfSW50IDwtIEFjb3VzdGljRGF0YSAlPiUKICBkcGx5cjo6ZmlsdGVyKCFncmVwbCgiX3JlbCIsIFNwZWFrZXIpKSAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoU3BlYWtlcikgJT4lCiAgZHBseXI6Om11dGF0ZShzZWdNaW4gPSBiYXNlOjptaW4oVkFTLCB0cmFuc0FjYyksCiAgICAgICAgICAgICAgICBzZWdNYXggPSBiYXNlOjptYXgoVkFTLCB0cmFuc0FjYyksCiAgICAgICAgICAgICAgICByYXRpbmdBdmcgPSBtZWFuKFZBUywgdHJhbnNBY2MsIG5hLnJtID0gVCksCiAgICAgICAgICAgICAgICBTcGVha2VyID0gYXMuZmFjdG9yKFNwZWFrZXIpLAogICAgICAgICAgICAgICAgRXRpb2xvZ3kgPSBjYXNlX3doZW4oCiAgICAgICAgICAgICAgICAgIEV0aW9sb2d5ID09ICJBdGF4aWMiIH4gIkF0YXhpYSIsCiAgICAgICAgICAgICAgICAgIFRSVUUgfiBhcy5jaGFyYWN0ZXIoRXRpb2xvZ3kpCiAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgRXRpb2xvZ3kgPSBhcy5mYWN0b3IoRXRpb2xvZ3kpKSAlPiUKICBhcnJhbmdlKHNlZ01heCkKCm15X3BhbCA8LSBjKCIjZjI2NDMwIiwgIiMyNzJEMkQiLCIjMjU2ZWZmIikKIyBXaXRoIGEgYml0IG1vcmUgc3R5bGUKcGxvdF9JbnQgPC0gZ2dwbG90KHBsb3REYXRhX0ludCkgKwogIGdlb21fc2VnbWVudChhZXMoeCA9IGZjdF9pbm9yZGVyKFNwZWFrZXIpLAogICAgICAgICAgICAgICAgICAgeGVuZCA9IFNwZWFrZXIsCiAgICAgICAgICAgICAgICAgICB5ID0gc2VnTWluLAogICAgICAgICAgICAgICAgICAgeWVuZCA9IHNlZ01heCwKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gRXRpb2xvZ3kpKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IFNwZWFrZXIsCiAgICAgICAgICAgICAgICAgeSA9IFZBUywKICAgICAgICAgICAgICAgICBjb2xvciA9IEV0aW9sb2d5KSwKICAgICAgICAgICAgICNjb2xvciA9IG15X3BhbFsxXSwKICAgICAgICAgICAgIHNpemUgPSAzLAogICAgICAgICAgICAgc2hhcGUgPSAxOSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBTcGVha2VyLAogICAgICAgICAgICAgICAgIHkgPSB0cmFuc0FjYywKICAgICAgICAgICAgICAgICBjb2xvciA9IEV0aW9sb2d5KSwKICAgICAgICAgICAgICNjb2xvciA9IG15X3BhbFsyXSwKICAgICAgICAgICAgIHNpemUgPSAzLAogICAgICAgICAgICAgc2hhcGUgPSAxNSkgKwogIGNvb3JkX2ZsaXAoKSsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICkgKwogIHhsYWIoIiIpICsKICB5bGFiKCJTcGVlY2ggSW50ZWxsaWdpYmlsaXR5IikgKwogIGdndGl0bGUoIlNwZWVjaCBJbnRlbGxpZ2liaWxpdHkiKSArCiAgeWxpbShjKDAsMTAwKSkKCgpteVBhbCA8LSBjKCIjMUFBRDc3IiwgIiMxMjc5QjUiLCAiI0ZGQkYwMCIsICIjRkQ3ODUzIiwgIiNCRjMxNzgiKQpteVNoYXBlcyA8LSBjKDE2LCAxOCwgMTcsIDE1KQoKT1RfVkFTc2NhdHRlciA8LSBnZ3Bsb3QocGxvdERhdGFfSW50LAogICAgICAgICAgICAgICAgICBhZXMoeCA9IFZBUywKICAgICAgICAgICAgICAgICAgICAgIHkgPSB0cmFuc0FjYywKICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gRXRpb2xvZ3ksCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IEV0aW9sb2d5LAogICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSBFdGlvbG9neSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRikgKwogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSkgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDEwMCksIHlsaW0gPSBjKDAsMTAwKSkgKwogIGxhYnMoeCA9ICJJbnRlbGxpZ2liaWxpdHkgKFZBUykiLCB5ID0gIkludGVsbGlnaWJpbGl0eSAoT1QpIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBteVBhbCkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBteVNoYXBlcykgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUoYXNwZWN0LnJhdGlvPTEsCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJyaWdodCIpCgoKZ2dzYXZlKGZpbGVuYW1lID0gIlBsb3RzL09UIGFuZCBWQVMgU2NhdHRlcnBsb3QucG5nIiwKICAgICAgIHBsb3QgPSBPVF9WQVNzY2F0dGVyLAogICAgICAgaGVpZ2h0ID0gMy4yNSwKICAgICAgIHdpZHRoID0gNCwKICAgICAgIHVuaXRzID0gImluIiwKICAgICAgIHNjYWxlID0gMSkKCnJtKHNjYXR0ZXIxLCBzY2F0dGVyMiwgY29tYmluZWRTY2F0dGVyKQpgYGAKCiMjIE1vZGVsIFNjYXR0ZXJwbG90cwpgYGB7cn0KbW9kZWxGaWd1cmVEYXRhIDwtIEFjb3VzdGljRGF0YSAlPiUKICBkcGx5cjo6ZmlsdGVyKCFncmVwbCgiX3JlbCIsU3BlYWtlcikpICU+JQogIGRwbHlyOjpzZWxlY3QoU3BlYWtlciwgRXRpb2xvZ3ksIFNleCwgVlNBX2IsIHZvd2VsX0VEX2IsIEh1bGxfYiwgSHVsbF9iVlNEXzI1LCBIdWxsX2JWU0RfNzUsIFZBUywgdHJhbnNBY2MpICU+JQogIGRwbHlyOjptdXRhdGUoU3BlYWtlciA9IGFzLmZhY3RvcihTcGVha2VyKSwKICAgICAgICAgICAgICAgIEV0aW9sb2d5ID0gYXMuZmFjdG9yKEV0aW9sb2d5KSwKICAgICAgICAgICAgICAgIFNleCA9IGFzLmZhY3RvcihTZXgpKSAlPiUKICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGNvbHMgPSBWQVM6dHJhbnNBY2MsIG5hbWVzX3RvID0gIkludFR5cGUiLCB2YWx1ZXNfdG8gPSAiSW50IikgJT4lCiAgZHBseXI6Om11dGF0ZShJbnRUeXBlID0gY2FzZV93aGVuKAogICAgSW50VHlwZSA9PSAidHJhbnNBY2MiIH4gIk9UIiwKICAgIFRSVUUgfiAiVkFTIgogICksCiAgICAgICAgICAgICAgICBJbnRUeXBlID0gYXMuZmFjdG9yKEludFR5cGUpKQoKeWxhYmVsIDwtICJJbnRlbGxpZ2liaWxpdHkiCm15UGFsIDwtIGMoIiMyRDJEMzciLCAiIzEyNzlCNSIpCm15UGFsU2hhcGUgPC0gYygxOSwgMSkKClZTQSA8LSBtb2RlbEZpZ3VyZURhdGEgJT4lCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gVlNBX2IsCiAgICAgIHkgPSBJbnQsCiAgICAgIGNvbG9yID0gSW50VHlwZSwKICAgICAgc2hhcGUgPSBJbnRUeXBlLAogICAgICBsaW5ldHlwZSA9IEludFR5cGUpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVCwgZmlsbCA9ICJsaWdodCBncmV5IikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRikgKwogIHhsYWIoZXhwcmVzc2lvbigiVlNBIChCYXJrIl4yKiIpIikpICsKICB5bGFiKHlsYWJlbCkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLDEwMCkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIGFzcGVjdC5yYXRpbz0xKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IG15UGFsKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IG15UGFsU2hhcGUpICsKICBsYWJzKGNvbG9yPSJJbnRlbGxpZ2liaWxpdHkgVHlwZSIsCiAgICAgICBzaGFwZSA9ICJJbnRlbGxpZ2liaWxpdHkgVHlwZSIsCiAgICAgICBsaW5ldHlwZSA9ICJJbnRlbGxpZ2liaWxpdHkgVHlwZSIpCgpkaXNwIDwtIG1vZGVsRmlndXJlRGF0YSAlPiUKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSB2b3dlbF9FRF9iLAogICAgICB5ID0gSW50LAogICAgICBjb2xvciA9IEludFR5cGUsCiAgICAgIHNoYXBlID0gSW50VHlwZSwKICAgICAgbGluZXR5cGUgPSBJbnRUeXBlKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IFQsIGZpbGwgPSAibGlnaHQgZ3JleSIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEYpICsKICB4bGFiKCJDb3JuZXIgRGlzcGVyc2lvbiAoQmFyaykiKSArCiAgeWxhYih5bGFiZWwpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwxMDApKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShhc3BlY3QucmF0aW89MSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBteVBhbCkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBteVBhbFNoYXBlKSArCiAgbGFicyhjb2xvcj0iSW50ZWxsaWdpYmlsaXR5IFR5cGUiLAogICAgICAgc2hhcGUgPSAiSW50ZWxsaWdpYmlsaXR5IFR5cGUiLAogICAgICAgbGluZXR5cGUgPSAiSW50ZWxsaWdpYmlsaXR5IFR5cGUiKQoKSHVsbCA8LSBtb2RlbEZpZ3VyZURhdGEgJT4lCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gSHVsbF9iLAogICAgICB5ID0gSW50LAogICAgICBjb2xvciA9IEludFR5cGUsCiAgICAgIHNoYXBlID0gSW50VHlwZSwKICAgICAgbGluZXR5cGUgPSBJbnRUeXBlKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IFQsIGZpbGwgPSAibGlnaHQgZ3JleSIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEYpICsKICB4bGFiKGV4cHJlc3Npb24oIlZTQSJbSHVsbF0qIiAoQmFyayJeMioiKSIpKSArCiAgeWxhYih5bGFiZWwpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwxMDApKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShhc3BlY3QucmF0aW89MSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gbXlQYWwpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gbXlQYWxTaGFwZSkgKwogIGxhYnMoY29sb3I9IkludGVsbGlnaWJpbGl0eSBUeXBlIiwKICAgICAgIHNoYXBlID0gIkludGVsbGlnaWJpbGl0eSBUeXBlIiwKICAgICAgIGxpbmV0eXBlID0gIkludGVsbGlnaWJpbGl0eSBUeXBlIikKCnZzZDI1IDwtIG1vZGVsRmlndXJlRGF0YSAlPiUKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBIdWxsX2JWU0RfMjUsCiAgICAgIHkgPSBJbnQsCiAgICAgIGNvbG9yID0gSW50VHlwZSwKICAgICAgc2hhcGUgPSBJbnRUeXBlLAogICAgICBsaW5ldHlwZSA9IEludFR5cGUpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVCwgZmlsbCA9ICJsaWdodCBncmV5IikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRikgKwogIHhsYWIoZXhwcmVzc2lvbigiVlNEIlsyNV0qIiAoQmFyayJeMioiKSIpKSArCiAgeWxhYih5bGFiZWwpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwxMDApKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShhc3BlY3QucmF0aW89MSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gbXlQYWwpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gbXlQYWxTaGFwZSkgKwogIGxhYnMoY29sb3I9IkludGVsbGlnaWJpbGl0eSBUeXBlIiwKICAgICAgIHNoYXBlID0gIkludGVsbGlnaWJpbGl0eSBUeXBlIiwKICAgICAgIGxpbmV0eXBlID0gIkludGVsbGlnaWJpbGl0eSBUeXBlIikKCnZzZDc1IDwtIG1vZGVsRmlndXJlRGF0YSAlPiUKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBIdWxsX2JWU0RfNzUsCiAgICAgIHkgPSBJbnQsCiAgICAgIGNvbG9yID0gSW50VHlwZSwKICAgICAgc2hhcGUgPSBJbnRUeXBlLAogICAgICBsaW5ldHlwZSA9IEludFR5cGUpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVCwgZmlsbCA9ICJsaWdodCBncmV5IikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRikgKwogIHhsYWIoZXhwcmVzc2lvbigiVlNEIls3NV0qIiAoQmFyayJeMioiKSIpKSArCiAgeWxhYih5bGFiZWwpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwxMDApKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShhc3BlY3QucmF0aW89MSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gbXlQYWwpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gbXlQYWxTaGFwZSkgKwogIGxhYnMoY29sb3I9IkludGVsbGlnaWJpbGl0eSBUeXBlIiwKICAgICAgIHNoYXBlID0gIkludGVsbGlnaWJpbGl0eSBUeXBlIiwKICAgICAgIGxpbmV0eXBlID0gIkludGVsbGlnaWJpbGl0eSBUeXBlIikKCiMgQ3JlYXRpbmcgT1QgU2NhdHRlcnBsb3QgRmlndXJlCgpzY2F0dGVyIDwtIFZTQSAgKyBkaXNwICsgcGF0Y2h3b3JrOjpndWlkZV9hcmVhKCkgKyBIdWxsICsgdnNkMjUgKyB2c2Q3NSArCiAgcGF0Y2h3b3JrOjpwbG90X2xheW91dChndWlkZXMgPSAnY29sbGVjdCcsCiAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMykgJiB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQpzY2F0dGVyIAoKZ2dzYXZlKCJQbG90cy9Nb2RlbEZpZ3VyZS5wbmciLCBzY2F0dGVyLAogICAgICAgaGVpZ2h0ID0gNCwKICAgICAgIHdpZHRoID0gNiwKICAgICAgIHVuaXRzID0gImluIiwKICAgICAgIHNjYWxlID0gMS4xKQpgYGAKCiMjIEZpbHRlcmluZyBhdCBEaWZmZXJlbnQgTGV2ZWxzCmBgYHtyfQp0ZXh0X3ggPC0gMTIuNQp0ZXh0X3kgPC0gOC41CnhsaW1zIDwtIGMoMTYsNSkKeWxpbXMgPC0gYyg5LDEpCiMgSHVsbCAtIDIgU0QgLS0tLQpQaXRjaF9QUkFBVCA8LSBsaXN0LmZpbGVzKHBhdGggPSBwYXN0ZSgiUHJlcHBlZCBEYXRhL0V4YW1wbGUgRGF0YSIsIHNlcCA9ICIiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLlBpdGNoIiwgaWdub3JlLmNhc2UgPSBUKSAlPiUKICAgIHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsLiwgc2VwID0gIiIpICU+JQogICAgcmVhZC5kZWxpbSguLCBoZWFkZXIgPSBGKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoUGl0Y2ggPSBWMSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKFBpdGNoID0gZ3N1YigiLS11bmRlZmluZWQtLSIsTkEsUGl0Y2gpLAogICAgICAgICAgICAgICAgICBQaXRjaCA9IGFzLm51bWVyaWMoUGl0Y2gpKQoKRm9ybWFudHNfUFJBQVQgPC0gbGlzdC5maWxlcyhwYXRoID0gcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEiLCBzZXAgPSAiIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIl9Gb3JtYW50IiwgaWdub3JlLmNhc2UgPSBUKSAlPiUKICAgIHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsLiwgc2VwID0gIiIpICU+JQogICAgcmVhZC5kZWxpbSguLCBoZWFkZXIgPSBUKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoIWMobmZvcm1hbnRzLCBCMS5Iei4sIEIyLkh6LiwgQjMuSHouLCBGNC5Iei4sIEI0Lkh6LiwgRjUuSHouLCBCNS5Iei4pKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoVGltZV9zID0gdGltZS5zLiwKICAgICAgICAgICAgICAgICAgRjFfSHogPSBGMS5Iei4sCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gRjIuSHouLAogICAgICAgICAgICAgICAgICBGM19IeiA9IEYzLkh6LikgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX0h6ID0gaWZlbHNlKEYxX0h6ID09IDAsIE5BLCBGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gaWZlbHNlKEYyX0h6ID09IDAsIE5BLCBGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gaWZlbHNlKEYzX0h6ID09IDAsIE5BLCBGM19IeikpICU+JQogICAgZHBseXI6Om11dGF0ZShGMV9IeiA9IGFzLm51bWVyaWMoRjFfSHopLAogICAgICAgICAgICAgICAgICBGMl9IeiA9IGFzLm51bWVyaWMoRjJfSHopLAogICAgICAgICAgICAgICAgICBGM19IeiA9IHN1cHByZXNzV2FybmluZ3MoYXMubnVtZXJpYyhGM19IeikpLAogICAgICAgICAgICAgICAgICBUaW1lX21zID0gVGltZV9zIC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjFfa0h6ID0gRjFfSHogLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMl9rSHogPSBGMl9IeiAvIDEwMDAsCiAgICAgICAgICAgICAgICAgIEYzX2tIeiA9IEYzX0h6IC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjFfYiA9IGVtdVI6OmJhcmsoRjFfSHopLAogICAgICAgICAgICAgICAgICBGMl9iID0gZW11Ujo6YmFyayhGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX2IgPSBlbXVSOjpiYXJrKEYzX0h6KSkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KCFUaW1lX3MpICU+JQogICAgZHBseXI6OnJlbG9jYXRlKFRpbWVfbXMsIC5iZWZvcmUgPSBGMV9IeikgJT4lCiAgICBjYmluZCguLFBpdGNoX1BSQUFUKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKFBpdGNoKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX21hZCA9IChhYnMoRjFfSHogLSBtZWRpYW4oRjFfSHopKS8gbWFkKEYxX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41LAogICAgICAgICAgICAgICAgICBGMl9tYWQgPSAoYWJzKEYyX0h6IC0gbWVkaWFuKEYyX0h6KSkvIG1hZChGMl9IeiwgY29uc3RhbnQgPSAxLjQ4MjYpKSA+IDIuNSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKEYxX21hZCA9PSBGQUxTRSAmIEYyX21hZCA9PSBGQUxTRSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKG1EaXN0ID0gbWFoYWxhbm9iaXMoY2JpbmQoLiRGMV9IeiwgLiRGMl9IeiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sTWVhbnMoY2JpbmQoLiRGMV9IeiwgLiRGMl9IeikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdiA9IGNvdihjYmluZCguJEYxX0h6LCAuJEYyX0h6KSkpLAogICAgICAgICAgICAgICAgICBtRGlzdF9zZCA9IGFicyhzY2FsZShtRGlzdCxjZW50ZXIgPSBUKSkpICU+JQogICAgI2RwbHlyOjptdXRhdGUobURpc3RPdXRsaWVyID0gKHN0YXRzOjpwY2hpc3EobURpc3QsIGRmPTEsIGxvd2VyLnRhaWw9RkFMU0UpKSA8IC4wMDEpICU+JQogICAgZHBseXI6OmZpbHRlcihtRGlzdF9zZCA8IDIpCiAgCiAgYyA8LSAyCiAgd2hpbGUoYyA8IE5ST1coRm9ybWFudHNfUFJBQVQpKXsKICAgIEZvcm1hbnRzX1BSQUFUJEYxX0h6W2NdIDwtIGlmZWxzZShpcy5uYShGb3JtYW50c19QUkFBVCRGMV9IeltjLTFdKSAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoRm9ybWFudHNfUFJBQVQkRjFfSHpbYysxXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRm9ybWFudHNfUFJBQVQkRjFfSHpbY10pCiAgICBGb3JtYW50c19QUkFBVCRGMl9IeltjXSA8LSBpZmVsc2UoaXMubmEoRm9ybWFudHNfUFJBQVQkRjJfSHpbYy0xXSkgJiYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYyX0h6W2MrMV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZvcm1hbnRzX1BSQUFUJEYyX0h6W2NdKQogICAgYyA8LSBjICsgMQogIH0KICBybShjKQogIAogICAgSHVsbF9iIDwtIGNIdWxsKEZvcm1hbnRzX1BSQUFUJEYxX2IsIEZvcm1hbnRzX1BSQUFUJEYyX2IpCiMjIyBQbG90dGluZyBIdWxsCiAgICAgIGNvbnZleENvb3JkcyA8LSBGb3JtYW50c19QUkFBVCAlPiUKICAgICAgICBkcGx5cjo6c2VsZWN0KEYxX2IsIEYyX2IpICU+JQogICAgICAgIGFzLm1hdHJpeCgpICU+JQogICAgICAgIGdyRGV2aWNlczo6Y2h1bGwoKQogICAgICBjb252ZXggPC0gRm9ybWFudHNfUFJBQVQgJT4lCiAgICAgICAgc2xpY2UoY29udmV4Q29vcmRzKQoKICAgICAgaHVsbFBsb3RfMiA8LSBnZ3Bsb3QoYWVzKEYyX2IsIEYxX2IpLAogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IEZvcm1hbnRzX1BSQUFUKSArCiAgICAgICAgZ2VvbV9wb2ludChzaGFwZSA9IDIxKSArCiAgICAgICAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBjb252ZXgsCiAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gLjUsCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIiMxMjc5QjUiLAogICAgICAgICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxLjUpICsKICAgICAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSB0ZXh0X3gsIHkgPSB0ZXh0X3ksIGxhYmVsID0gcGFzdGUoIkh1bGwgPSIscm91bmQoSHVsbF9iLDIpKSkgKwogICAgICAgIHNjYWxlX3lfcmV2ZXJzZSgpICsKICAgICAgICBzY2FsZV94X3JldmVyc2UoKSArCiAgICAgICAgeGxpbSh4bGltcykgKwogICAgICAgIHlsaW0oeWxpbXMpICsKICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIjIgU0QiKSkgKyB4bGFiKCJGMiAoQmFyaykiKSArIHlsYWIoIkYxIChCYXJrKSIpICsKICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgICAgICBhc3BlY3QucmF0aW8gPSAxKQogICAgICBodWxsUGxvdF8yCiAgICAgIAojIEh1bGwgLSAyLjUgU0QgLS0tLQpQaXRjaF9QUkFBVCA8LSBsaXN0LmZpbGVzKHBhdGggPSBwYXN0ZSgiUHJlcHBlZCBEYXRhL0V4YW1wbGUgRGF0YSIsIHNlcCA9ICIiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLlBpdGNoIiwgaWdub3JlLmNhc2UgPSBUKSAlPiUKICAgIHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsLiwgc2VwID0gIiIpICU+JQogICAgcmVhZC5kZWxpbSguLCBoZWFkZXIgPSBGKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoUGl0Y2ggPSBWMSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKFBpdGNoID0gZ3N1YigiLS11bmRlZmluZWQtLSIsTkEsUGl0Y2gpLAogICAgICAgICAgICAgICAgICBQaXRjaCA9IGFzLm51bWVyaWMoUGl0Y2gpKQoKRm9ybWFudHNfUFJBQVQgPC0gbGlzdC5maWxlcyhwYXRoID0gcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEiLCBzZXAgPSAiIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIl9Gb3JtYW50IiwgaWdub3JlLmNhc2UgPSBUKSAlPiUKICAgIHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsLiwgc2VwID0gIiIpICU+JQogICAgcmVhZC5kZWxpbSguLCBoZWFkZXIgPSBUKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoIWMobmZvcm1hbnRzLCBCMS5Iei4sIEIyLkh6LiwgQjMuSHouLCBGNC5Iei4sIEI0Lkh6LiwgRjUuSHouLCBCNS5Iei4pKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoVGltZV9zID0gdGltZS5zLiwKICAgICAgICAgICAgICAgICAgRjFfSHogPSBGMS5Iei4sCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gRjIuSHouLAogICAgICAgICAgICAgICAgICBGM19IeiA9IEYzLkh6LikgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX0h6ID0gaWZlbHNlKEYxX0h6ID09IDAsIE5BLCBGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gaWZlbHNlKEYyX0h6ID09IDAsIE5BLCBGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gaWZlbHNlKEYzX0h6ID09IDAsIE5BLCBGM19IeikpICU+JQogICAgZHBseXI6Om11dGF0ZShGMV9IeiA9IGFzLm51bWVyaWMoRjFfSHopLAogICAgICAgICAgICAgICAgICBGMl9IeiA9IGFzLm51bWVyaWMoRjJfSHopLAogICAgICAgICAgICAgICAgICBGM19IeiA9IHN1cHByZXNzV2FybmluZ3MoYXMubnVtZXJpYyhGM19IeikpLAogICAgICAgICAgICAgICAgICBUaW1lX21zID0gVGltZV9zIC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjFfa0h6ID0gRjFfSHogLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMl9rSHogPSBGMl9IeiAvIDEwMDAsCiAgICAgICAgICAgICAgICAgIEYzX2tIeiA9IEYzX0h6IC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjFfYiA9IGVtdVI6OmJhcmsoRjFfSHopLAogICAgICAgICAgICAgICAgICBGMl9iID0gZW11Ujo6YmFyayhGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX2IgPSBlbXVSOjpiYXJrKEYzX0h6KSkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KCFUaW1lX3MpICU+JQogICAgZHBseXI6OnJlbG9jYXRlKFRpbWVfbXMsIC5iZWZvcmUgPSBGMV9IeikgJT4lCiAgICBjYmluZCguLFBpdGNoX1BSQUFUKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKFBpdGNoKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX21hZCA9IChhYnMoRjFfSHogLSBtZWRpYW4oRjFfSHopKS8gbWFkKEYxX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41LAogICAgICAgICAgICAgICAgICBGMl9tYWQgPSAoYWJzKEYyX0h6IC0gbWVkaWFuKEYyX0h6KSkvIG1hZChGMl9IeiwgY29uc3RhbnQgPSAxLjQ4MjYpKSA+IDIuNSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKEYxX21hZCA9PSBGQUxTRSAmIEYyX21hZCA9PSBGQUxTRSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKG1EaXN0ID0gbWFoYWxhbm9iaXMoY2JpbmQoLiRGMV9IeiwgLiRGMl9IeiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sTWVhbnMoY2JpbmQoLiRGMV9IeiwgLiRGMl9IeikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdiA9IGNvdihjYmluZCguJEYxX0h6LCAuJEYyX0h6KSkpLAogICAgICAgICAgICAgICAgICBtRGlzdF9zZCA9IGFicyhzY2FsZShtRGlzdCxjZW50ZXIgPSBUKSkpICU+JQogICAgI2RwbHlyOjptdXRhdGUobURpc3RPdXRsaWVyID0gKHN0YXRzOjpwY2hpc3EobURpc3QsIGRmPTEsIGxvd2VyLnRhaWw9RkFMU0UpKSA8IC4wMDEpICU+JQogICAgZHBseXI6OmZpbHRlcihtRGlzdF9zZCA8IDIuNSkKICAKICBjIDwtIDIKICB3aGlsZShjIDwgTlJPVyhGb3JtYW50c19QUkFBVCkpewogICAgRm9ybWFudHNfUFJBQVQkRjFfSHpbY10gPC0gaWZlbHNlKGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYxX0h6W2MtMV0pICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpcy5uYShGb3JtYW50c19QUkFBVCRGMV9IeltjKzFdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGb3JtYW50c19QUkFBVCRGMV9IeltjXSkKICAgIEZvcm1hbnRzX1BSQUFUJEYyX0h6W2NdIDwtIGlmZWxzZShpcy5uYShGb3JtYW50c19QUkFBVCRGMl9IeltjLTFdKSAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoRm9ybWFudHNfUFJBQVQkRjJfSHpbYysxXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRm9ybWFudHNfUFJBQVQkRjJfSHpbY10pCiAgICBjIDwtIGMgKyAxCiAgfQogIHJtKGMpCiAgCiAgICBIdWxsX2IgPC0gY0h1bGwoRm9ybWFudHNfUFJBQVQkRjFfYiwgRm9ybWFudHNfUFJBQVQkRjJfYikKIyMjIFBsb3R0aW5nIEh1bGwKICAgICAgY29udmV4Q29vcmRzIDwtIEZvcm1hbnRzX1BSQUFUICU+JQogICAgICAgIGRwbHlyOjpzZWxlY3QoRjFfYiwgRjJfYikgJT4lCiAgICAgICAgYXMubWF0cml4KCkgJT4lCiAgICAgICAgZ3JEZXZpY2VzOjpjaHVsbCgpCiAgICAgIGNvbnZleCA8LSBGb3JtYW50c19QUkFBVCAlPiUKICAgICAgICBzbGljZShjb252ZXhDb29yZHMpCgogICAgICBodWxsUGxvdF8yLjUgPC0gZ2dwbG90KGFlcyhGMl9iLCBGMV9iKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBGb3JtYW50c19QUkFBVCkgKwogICAgICAgIGdlb21fcG9pbnQoc2hhcGUgPSAyMSkgKwogICAgICAgIGdlb21fcG9seWdvbihkYXRhID0gY29udmV4LAogICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IC41LAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICIjMTI3OUI1IiwKICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IE5BLAogICAgICAgICAgICAgICAgICAgICBzaXplID0gMS41KSArCiAgICAgICAgYW5ub3RhdGUoInRleHQiLCB4ID0gdGV4dF94LCB5ID0gdGV4dF95LCBsYWJlbCA9IHBhc3RlKCJIdWxsID0iLHJvdW5kKEh1bGxfYiwyKSkpICsKICAgICAgICBzY2FsZV95X3JldmVyc2UoKSArCiAgICAgICAgc2NhbGVfeF9yZXZlcnNlKCkgKwogICAgICAgIHhsaW0oeGxpbXMpICsKICAgICAgICB5bGltKHlsaW1zKSArCiAgICAgICAgdGhlbWVfY2xhc3NpYygpICsgbGFicyh0aXRsZSA9IHBhc3RlKCIyLjUgU0QiKSkgKyB4bGFiKCJGMiAoQmFyaykiKSArIHlsYWIoIkYxIChCYXJrKSIpICsKICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgICAgICBhc3BlY3QucmF0aW8gPSAxKQogICAgICBodWxsUGxvdF8yLjUKICAgICAgCiMgSHVsbCAtIDMgU0QgLS0tLQpQaXRjaF9QUkFBVCA8LSBsaXN0LmZpbGVzKHBhdGggPSBwYXN0ZSgiUHJlcHBlZCBEYXRhL0V4YW1wbGUgRGF0YSIsIHNlcCA9ICIiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLlBpdGNoIiwgaWdub3JlLmNhc2UgPSBUKSAlPiUKICAgIHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsLiwgc2VwID0gIiIpICU+JQogICAgcmVhZC5kZWxpbSguLCBoZWFkZXIgPSBGKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoUGl0Y2ggPSBWMSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKFBpdGNoID0gZ3N1YigiLS11bmRlZmluZWQtLSIsTkEsUGl0Y2gpLAogICAgICAgICAgICAgICAgICBQaXRjaCA9IGFzLm51bWVyaWMoUGl0Y2gpKQoKRm9ybWFudHNfUFJBQVQgPC0gbGlzdC5maWxlcyhwYXRoID0gcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEiLCBzZXAgPSAiIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIl9Gb3JtYW50IiwgaWdub3JlLmNhc2UgPSBUKSAlPiUKICAgIHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsLiwgc2VwID0gIiIpICU+JQogICAgcmVhZC5kZWxpbSguLCBoZWFkZXIgPSBUKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoIWMobmZvcm1hbnRzLCBCMS5Iei4sIEIyLkh6LiwgQjMuSHouLCBGNC5Iei4sIEI0Lkh6LiwgRjUuSHouLCBCNS5Iei4pKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoVGltZV9zID0gdGltZS5zLiwKICAgICAgICAgICAgICAgICAgRjFfSHogPSBGMS5Iei4sCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gRjIuSHouLAogICAgICAgICAgICAgICAgICBGM19IeiA9IEYzLkh6LikgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX0h6ID0gaWZlbHNlKEYxX0h6ID09IDAsIE5BLCBGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gaWZlbHNlKEYyX0h6ID09IDAsIE5BLCBGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gaWZlbHNlKEYzX0h6ID09IDAsIE5BLCBGM19IeikpICU+JQogICAgZHBseXI6Om11dGF0ZShGMV9IeiA9IGFzLm51bWVyaWMoRjFfSHopLAogICAgICAgICAgICAgICAgICBGMl9IeiA9IGFzLm51bWVyaWMoRjJfSHopLAogICAgICAgICAgICAgICAgICBGM19IeiA9IHN1cHByZXNzV2FybmluZ3MoYXMubnVtZXJpYyhGM19IeikpLAogICAgICAgICAgICAgICAgICBUaW1lX21zID0gVGltZV9zIC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjFfa0h6ID0gRjFfSHogLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMl9rSHogPSBGMl9IeiAvIDEwMDAsCiAgICAgICAgICAgICAgICAgIEYzX2tIeiA9IEYzX0h6IC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjFfYiA9IGVtdVI6OmJhcmsoRjFfSHopLAogICAgICAgICAgICAgICAgICBGMl9iID0gZW11Ujo6YmFyayhGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX2IgPSBlbXVSOjpiYXJrKEYzX0h6KSkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KCFUaW1lX3MpICU+JQogICAgZHBseXI6OnJlbG9jYXRlKFRpbWVfbXMsIC5iZWZvcmUgPSBGMV9IeikgJT4lCiAgICBjYmluZCguLFBpdGNoX1BSQUFUKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKFBpdGNoKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX21hZCA9IChhYnMoRjFfSHogLSBtZWRpYW4oRjFfSHopKS8gbWFkKEYxX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41LAogICAgICAgICAgICAgICAgICBGMl9tYWQgPSAoYWJzKEYyX0h6IC0gbWVkaWFuKEYyX0h6KSkvIG1hZChGMl9IeiwgY29uc3RhbnQgPSAxLjQ4MjYpKSA+IDIuNSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKEYxX21hZCA9PSBGQUxTRSAmIEYyX21hZCA9PSBGQUxTRSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKG1EaXN0ID0gbWFoYWxhbm9iaXMoY2JpbmQoLiRGMV9IeiwgLiRGMl9IeiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sTWVhbnMoY2JpbmQoLiRGMV9IeiwgLiRGMl9IeikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdiA9IGNvdihjYmluZCguJEYxX0h6LCAuJEYyX0h6KSkpLAogICAgICAgICAgICAgICAgICBtRGlzdF9zZCA9IGFicyhzY2FsZShtRGlzdCxjZW50ZXIgPSBUKSkpICU+JQogICAgI2RwbHlyOjptdXRhdGUobURpc3RPdXRsaWVyID0gKHN0YXRzOjpwY2hpc3EobURpc3QsIGRmPTEsIGxvd2VyLnRhaWw9RkFMU0UpKSA8IC4wMDEpICU+JQogICAgZHBseXI6OmZpbHRlcihtRGlzdF9zZCA8IDMpCiAgCiAgYyA8LSAyCiAgd2hpbGUoYyA8IE5ST1coRm9ybWFudHNfUFJBQVQpKXsKICAgIEZvcm1hbnRzX1BSQUFUJEYxX0h6W2NdIDwtIGlmZWxzZShpcy5uYShGb3JtYW50c19QUkFBVCRGMV9IeltjLTFdKSAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoRm9ybWFudHNfUFJBQVQkRjFfSHpbYysxXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRm9ybWFudHNfUFJBQVQkRjFfSHpbY10pCiAgICBGb3JtYW50c19QUkFBVCRGMl9IeltjXSA8LSBpZmVsc2UoaXMubmEoRm9ybWFudHNfUFJBQVQkRjJfSHpbYy0xXSkgJiYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYyX0h6W2MrMV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZvcm1hbnRzX1BSQUFUJEYyX0h6W2NdKQogICAgYyA8LSBjICsgMQogIH0KICBybShjKQogIAogICAgSHVsbF9iIDwtIGNIdWxsKEZvcm1hbnRzX1BSQUFUJEYxX2IsIEZvcm1hbnRzX1BSQUFUJEYyX2IpCiMjIyBQbG90dGluZyBIdWxsCiAgICAgIGNvbnZleENvb3JkcyA8LSBGb3JtYW50c19QUkFBVCAlPiUKICAgICAgICBkcGx5cjo6c2VsZWN0KEYxX2IsIEYyX2IpICU+JQogICAgICAgIGFzLm1hdHJpeCgpICU+JQogICAgICAgIGdyRGV2aWNlczo6Y2h1bGwoKQogICAgICBjb252ZXggPC0gRm9ybWFudHNfUFJBQVQgJT4lCiAgICAgICAgc2xpY2UoY29udmV4Q29vcmRzKQoKICAgICAgaHVsbFBsb3RfMyA8LSBnZ3Bsb3QoYWVzKEYyX2IsIEYxX2IpLAogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IEZvcm1hbnRzX1BSQUFUKSArCiAgICAgICAgZ2VvbV9wb2ludChzaGFwZSA9IDIxKSArCiAgICAgICAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBjb252ZXgsCiAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gLjUsCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIiMxMjc5QjUiLAogICAgICAgICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxLjUpICsKICAgICAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSB0ZXh0X3gsIHkgPSB0ZXh0X3ksIGxhYmVsID0gcGFzdGUoIkh1bGwgPSIscm91bmQoSHVsbF9iLDIpKSkgKwogICAgICAgIHNjYWxlX3lfcmV2ZXJzZSgpICsKICAgICAgICBzY2FsZV94X3JldmVyc2UoKSArCiAgICAgICAgeGxpbSh4bGltcykgKwogICAgICAgIHlsaW0oeWxpbXMpICsKICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIjMgU0QiKSkgKyB4bGFiKCJGMiAoQmFyaykiKSArIHlsYWIoIkYxIChCYXJrKSIpICsKICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgICAgICBhc3BlY3QucmF0aW8gPSAxKQogICAgICBodWxsUGxvdF8zCiAgICAgIAojIEh1bGwgLSAxLjUgU0QgLS0tLQpQaXRjaF9QUkFBVCA8LSBsaXN0LmZpbGVzKHBhdGggPSBwYXN0ZSgiUHJlcHBlZCBEYXRhL0V4YW1wbGUgRGF0YSIsIHNlcCA9ICIiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLlBpdGNoIiwgaWdub3JlLmNhc2UgPSBUKSAlPiUKICAgIHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsLiwgc2VwID0gIiIpICU+JQogICAgcmVhZC5kZWxpbSguLCBoZWFkZXIgPSBGKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoUGl0Y2ggPSBWMSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKFBpdGNoID0gZ3N1YigiLS11bmRlZmluZWQtLSIsTkEsUGl0Y2gpLAogICAgICAgICAgICAgICAgICBQaXRjaCA9IGFzLm51bWVyaWMoUGl0Y2gpKQoKRm9ybWFudHNfUFJBQVQgPC0gbGlzdC5maWxlcyhwYXRoID0gcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEiLCBzZXAgPSAiIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIl9Gb3JtYW50IiwgaWdub3JlLmNhc2UgPSBUKSAlPiUKICAgIHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsLiwgc2VwID0gIiIpICU+JQogICAgcmVhZC5kZWxpbSguLCBoZWFkZXIgPSBUKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoIWMobmZvcm1hbnRzLCBCMS5Iei4sIEIyLkh6LiwgQjMuSHouLCBGNC5Iei4sIEI0Lkh6LiwgRjUuSHouLCBCNS5Iei4pKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoVGltZV9zID0gdGltZS5zLiwKICAgICAgICAgICAgICAgICAgRjFfSHogPSBGMS5Iei4sCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gRjIuSHouLAogICAgICAgICAgICAgICAgICBGM19IeiA9IEYzLkh6LikgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX0h6ID0gaWZlbHNlKEYxX0h6ID09IDAsIE5BLCBGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gaWZlbHNlKEYyX0h6ID09IDAsIE5BLCBGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gaWZlbHNlKEYzX0h6ID09IDAsIE5BLCBGM19IeikpICU+JQogICAgZHBseXI6Om11dGF0ZShGMV9IeiA9IGFzLm51bWVyaWMoRjFfSHopLAogICAgICAgICAgICAgICAgICBGMl9IeiA9IGFzLm51bWVyaWMoRjJfSHopLAogICAgICAgICAgICAgICAgICBGM19IeiA9IHN1cHByZXNzV2FybmluZ3MoYXMubnVtZXJpYyhGM19IeikpLAogICAgICAgICAgICAgICAgICBUaW1lX21zID0gVGltZV9zIC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjFfa0h6ID0gRjFfSHogLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMl9rSHogPSBGMl9IeiAvIDEwMDAsCiAgICAgICAgICAgICAgICAgIEYzX2tIeiA9IEYzX0h6IC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjFfYiA9IGVtdVI6OmJhcmsoRjFfSHopLAogICAgICAgICAgICAgICAgICBGMl9iID0gZW11Ujo6YmFyayhGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX2IgPSBlbXVSOjpiYXJrKEYzX0h6KSkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KCFUaW1lX3MpICU+JQogICAgZHBseXI6OnJlbG9jYXRlKFRpbWVfbXMsIC5iZWZvcmUgPSBGMV9IeikgJT4lCiAgICBjYmluZCguLFBpdGNoX1BSQUFUKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKFBpdGNoKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX21hZCA9IChhYnMoRjFfSHogLSBtZWRpYW4oRjFfSHopKS8gbWFkKEYxX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41LAogICAgICAgICAgICAgICAgICBGMl9tYWQgPSAoYWJzKEYyX0h6IC0gbWVkaWFuKEYyX0h6KSkvIG1hZChGMl9IeiwgY29uc3RhbnQgPSAxLjQ4MjYpKSA+IDIuNSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKEYxX21hZCA9PSBGQUxTRSAmIEYyX21hZCA9PSBGQUxTRSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKG1EaXN0ID0gbWFoYWxhbm9iaXMoY2JpbmQoLiRGMV9IeiwgLiRGMl9IeiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sTWVhbnMoY2JpbmQoLiRGMV9IeiwgLiRGMl9IeikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdiA9IGNvdihjYmluZCguJEYxX0h6LCAuJEYyX0h6KSkpLAogICAgICAgICAgICAgICAgICBtRGlzdF9zZCA9IGFicyhzY2FsZShtRGlzdCxjZW50ZXIgPSBUKSkpICU+JQogICAgI2RwbHlyOjptdXRhdGUobURpc3RPdXRsaWVyID0gKHN0YXRzOjpwY2hpc3EobURpc3QsIGRmPTEsIGxvd2VyLnRhaWw9RkFMU0UpKSA8IC4wMDEpICU+JQogICAgZHBseXI6OmZpbHRlcihtRGlzdF9zZCA8IDEuNSkKICAKICBjIDwtIDIKICB3aGlsZShjIDwgTlJPVyhGb3JtYW50c19QUkFBVCkpewogICAgRm9ybWFudHNfUFJBQVQkRjFfSHpbY10gPC0gaWZlbHNlKGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYxX0h6W2MtMV0pICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpcy5uYShGb3JtYW50c19QUkFBVCRGMV9IeltjKzFdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGb3JtYW50c19QUkFBVCRGMV9IeltjXSkKICAgIEZvcm1hbnRzX1BSQUFUJEYyX0h6W2NdIDwtIGlmZWxzZShpcy5uYShGb3JtYW50c19QUkFBVCRGMl9IeltjLTFdKSAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoRm9ybWFudHNfUFJBQVQkRjJfSHpbYysxXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRm9ybWFudHNfUFJBQVQkRjJfSHpbY10pCiAgICBjIDwtIGMgKyAxCiAgfQogIHJtKGMpCiAgCiAgICBIdWxsX2IgPC0gY0h1bGwoRm9ybWFudHNfUFJBQVQkRjFfYiwgRm9ybWFudHNfUFJBQVQkRjJfYikKIyMjIFBsb3R0aW5nIEh1bGwKICAgICAgY29udmV4Q29vcmRzIDwtIEZvcm1hbnRzX1BSQUFUICU+JQogICAgICAgIGRwbHlyOjpzZWxlY3QoRjFfYiwgRjJfYikgJT4lCiAgICAgICAgYXMubWF0cml4KCkgJT4lCiAgICAgICAgZ3JEZXZpY2VzOjpjaHVsbCgpCiAgICAgIGNvbnZleCA8LSBGb3JtYW50c19QUkFBVCAlPiUKICAgICAgICBzbGljZShjb252ZXhDb29yZHMpCgogICAgICBodWxsUGxvdF8xLjUgPC0gZ2dwbG90KGFlcyhGMl9iLCBGMV9iKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBGb3JtYW50c19QUkFBVCkgKwogICAgICAgIGdlb21fcG9pbnQoc2hhcGUgPSAyMSkgKwogICAgICAgIGdlb21fcG9seWdvbihkYXRhID0gY29udmV4LAogICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IC41LAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICIjMTI3OUI1IiwKICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IE5BLAogICAgICAgICAgICAgICAgICAgICBzaXplID0gMS41KSArCiAgICAgICAgYW5ub3RhdGUoInRleHQiLCB4ID0gdGV4dF94LCB5ID0gdGV4dF95LCBsYWJlbCA9IHBhc3RlKCJIdWxsID0iLHJvdW5kKEh1bGxfYiwyKSkpICsKICAgICAgICBzY2FsZV95X3JldmVyc2UoKSArCiAgICAgICAgc2NhbGVfeF9yZXZlcnNlKCkgKwogICAgICAgIHhsaW0oeGxpbXMpICsKICAgICAgICB5bGltKHlsaW1zKSArCiAgICAgICAgdGhlbWVfY2xhc3NpYygpICsgbGFicyh0aXRsZSA9IHBhc3RlKCIxLjUgU0QiKSkgKyB4bGFiKCJGMiAoQmFyaykiKSArIHlsYWIoIkYxIChCYXJrKSIpICsKICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgICAgICBhc3BlY3QucmF0aW8gPSAxKQogICAgICBodWxsUGxvdF8xLjUKICAgICAgCiMgQ29tYmluZWQgLS0tLQogICAgICBnZ3B1YnI6OmdnYXJyYW5nZShodWxsUGxvdF8xLjUsIGh1bGxQbG90XzIsIGh1bGxQbG90XzIuNSwgaHVsbFBsb3RfMywKICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDQpCiAgICAgIGdnc2F2ZShmaWxlbmFtZSA9ICJQbG90cy9IdWxsIGF0IERpZmZlcmVudCBGaWx0ZXJzLnBuZyIsCiAgICAgICAgICAgICBoZWlnaHQgPSAzLAogICAgICAgICAgICAgd2lkdGg9IDksCiAgICAgICAgICAgICB1bml0cyA9ICJpbiIsCiAgICAgICAgICAgICBzY2FsZSA9IC45KQogICAgICAKYGBgCgojIExpc3RlbmVyIERlbW9ncmFwaGljIEluZm9ybWF0aW9uCmBgYHtyfQoKTGlzdGVuZXJEZW1vIDwtIExpc3RlbmVycyAlPiUKICBmdXJuaXR1cmU6OnRhYmxlMShhZ2UsIGdlbmRlciwgcmFjZSwgZXRobmljaXR5KQoKTGlzdGVuZXJEZW1vCgpgYGAKCiMgU3BlYWtlciBEZW1vZ3JhcGhpY3MKCmBgYHtyfQoKU3BlYWtlckRlbW8gPC0gQWNvdXN0aWNEYXRhICU+JQogIGRwbHlyOjpzZWxlY3QoYyhTcGVha2VyLCBTZXgsIEV0aW9sb2d5KSkKCkFnZXMgPC0gcmlvOjppbXBvcnQoIlByZXBwZWQgRGF0YS9TcGVha2VyIEFnZXMueGxzeCIpCgpTcGVha2VyRGVtbyA8LSBmdWxsX2pvaW4oU3BlYWtlckRlbW8sIEFnZXMsIGJ5ID0gIlNwZWFrZXIiKQoKU3BlYWtlckRlbW9JbmZvIDwtIFNwZWFrZXJEZW1vICU+JQogIGZ1cm5pdHVyZTo6dGFibGUxKFNleCwgRXRpb2xvZ3ksIEFnZSwgbmEucm0gPSBGKQoKU3BlYWtlckRlbW9JbmZvCgpTcGVha2VyRGVtbyAlPiUKICBkcGx5cjo6c3VtbWFyaXplKG1lYW5fYWdlID0gbWVhbihBZ2UsIG5hLnJtID0gVCksIGFnZV9zZCA9IHNkKEFnZSwgbmEucm0gPSBUKSwgYWdlX3JhbmdlID0gcmFuZ2UoQWdlLCBuYS5ybSA9IFQpKQoKYGBgCgo=